jsPDF.js ➔ decodestream_ensureBuffer   B
last analyzed

Complexity

Conditions 5
Paths 5

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
c 0
b 0
f 0
nc 5
dl 0
loc 13
rs 8.8571
nop 1
1
/** @preserve
2
 * jsPDF - PDF Document creation from JavaScript
3
 * Version 1.0.0-trunk Built on ${buildDate}
4
 * Commit ${commitID}
5
 *
6
 * Copyright (c) 2010-2014 James Hall, https://github.com/MrRio/jsPDF
7
 *               2010 Aaron Spike, https://github.com/acspike
8
 *               2012 Willow Systems Corporation, willow-systems.com
9
 *               2012 Pablo Hess, https://github.com/pablohess
10
 *               2012 Florian Jenett, https://github.com/fjenett
11
 *               2013 Warren Weckesser, https://github.com/warrenweckesser
12
 *               2013 Youssef Beddad, https://github.com/lifof
13
 *               2013 Lee Driscoll, https://github.com/lsdriscoll
14
 *               2013 Stefan Slonevskiy, https://github.com/stefslon
15
 *               2013 Jeremy Morel, https://github.com/jmorel
16
 *               2013 Christoph Hartmann, https://github.com/chris-rock
17
 *               2014 Juan Pablo Gaviria, https://github.com/juanpgaviria
18
 *               2014 James Makes, https://github.com/dollaruw
19
 *               2014 Diego Casorran, https://github.com/diegocr
20
 *
21
 * Permission is hereby granted, free of charge, to any person obtaining
22
 * a copy of this software and associated documentation files (the
23
 * "Software"), to deal in the Software without restriction, including
24
 * without limitation the rights to use, copy, modify, merge, publish,
25
 * distribute, sublicense, and/or sell copies of the Software, and to
26
 * permit persons to whom the Software is furnished to do so, subject to
27
 * the following conditions:
28
 *
29
 * The above copyright notice and this permission notice shall be
30
 * included in all copies or substantial portions of the Software.
31
 *
32
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
36
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
37
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
38
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39
 * 
40
 * Contributor(s):
41
 *    siefkenj, ahwolf, rickygu, Midnith, saintclair, eaparango,
42
 *    kim3er, mfo, alnorth, 
43
 */
44
45
/**
46
Creates new jsPDF document object instance
47
@class
48
@param orientation One of "portrait" or "landscape" (or shortcuts "p" (Default), "l")
49
@param unit Measurement unit to be used when coordinates are specified. One of "pt" (points), "mm" (Default), "cm", "in"
50
@param format One of 'a0', 'a1', 'a2', 'a3', 'a4' (Default) etc to 'a10', 'b0' to 'b10', 'c0' to 'c10', 'letter', 'government-letter', 'legal', 'junior-legal', 'ledger' or 'tabloid'
51
@returns {jsPDF}
52
@name jsPDF
53
*/
54
var jsPDF = (function (global) {
55
    'use strict';
56
    /*jslint browser:true, plusplus: true, bitwise: true, nomen: true */
57
    /*global document: false, btoa, atob, zpipe, Uint8Array, ArrayBuffer, Blob, saveAs, adler32cs, Deflater */
58
59
// this will run on <=IE9, possibly some niche browsers
60
// new webkit-based, FireFox, IE10 already have native version of this.
61
    if (typeof btoa === 'undefined') {
62
        global.btoa = function (data) {
63
        // DO NOT ADD UTF8 ENCODING CODE HERE!!!!
64
65
        // UTF8 encoding encodes bytes over char code 128
66
        // and, essentially, turns an 8-bit binary streams
67
        // (that base64 can deal with) into 7-bit binary streams.
68
        // (by default server does not know that and does not recode the data back to 8bit)
69
        // You destroy your data.
70
71
        // binary streams like jpeg image data etc, while stored in JavaScript strings,
72
        // (which are 16bit arrays) are in 8bit format already.
73
        // You do NOT need to char-encode that before base64 encoding.
74
75
        // if you, by act of fate
76
        // have string which has individual characters with code
77
        // above 255 (pure unicode chars), encode that BEFORE you base64 here.
78
        // you can use absolutely any approch there, as long as in the end,
79
        // base64 gets an 8bit (char codes 0 - 255) stream.
80
        // when you get it on the server after un-base64, you must
81
        // UNencode it too, to get back to 16, 32bit or whatever original bin stream.
82
83
        // Note, Yes, JavaScript strings are, in most cases UCS-2 -
84
        // 16-bit character arrays. This does not mean, however,
85
        // that you always have to UTF8 it before base64.
86
        // it means that if you have actual characters anywhere in
87
        // that string that have char code above 255, you need to
88
        // recode *entire* string from 16-bit (or 32bit) to 8-bit array.
89
        // You can do binary split to UTF16 (BE or LE)
90
        // you can do utf8, you can split the thing by hand and prepend BOM to it,
91
        // but whatever you do, make sure you mirror the opposite on
92
        // the server. If server does not expect to post-process un-base64
93
        // 8-bit binary stream, think very very hard about messing around with encoding.
94
95
        // so, long story short:
96
        // DO NOT ADD UTF8 ENCODING CODE HERE!!!!
97
98
        /* @preserve
99
        ====================================================================
100
        base64 encoder
101
        MIT, GPL
102
103
        version: 1109.2015
104
        discuss at: http://phpjs.org/functions/base64_encode
105
        +   original by: Tyler Akins (http://rumkin.com)
106
        +   improved by: Bayron Guevara
107
        +   improved by: Thunder.m
108
        +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
109
        +   bugfixed by: Pellentesque Malesuada
110
        +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
111
        +   improved by: Rafal Kukawski (http://kukawski.pl)
112
        +                Daniel Dotsenko, Willow Systems Corp, willow-systems.com
113
        ====================================================================
114
        */
115
116
            var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
117
                b64a = b64.split(''),
118
                o1,
119
                o2,
120
                o3,
121
                h1,
122
                h2,
123
                h3,
124
                h4,
125
                bits,
126
                i = 0,
127
                ac = 0,
128
                enc = "",
129
                tmp_arr = [],
130
                r;
131
132
            do { // pack three octets into four hexets
133
                o1 = data.charCodeAt(i++);
134
                o2 = data.charCodeAt(i++);
135
                o3 = data.charCodeAt(i++);
136
137
                bits = o1 << 16 | o2 << 8 | o3;
138
139
                h1 = bits >> 18 & 0x3f;
140
                h2 = bits >> 12 & 0x3f;
141
                h3 = bits >> 6 & 0x3f;
142
                h4 = bits & 0x3f;
143
144
                // use hexets to index into b64, and append result to encoded string
145
                tmp_arr[ac++] = b64a[h1] + b64a[h2] + b64a[h3] + b64a[h4];
146
            } while (i < data.length);
147
148
            enc = tmp_arr.join('');
149
            r = data.length % 3;
150
            return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
151
            // end of base64 encoder MIT, GPL
152
        };
153
    }
154
155
    if (typeof atob === 'undefined') {
156
        global.atob = function (data) {
157
        // http://kevin.vanzonneveld.net
158
        // +   original by: Tyler Akins (http://rumkin.com)
159
        // +   improved by: Thunder.m
160
        // +      input by: Aman Gupta
161
        // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
162
        // +   bugfixed by: Onno Marsman
163
        // +   bugfixed by: Pellentesque Malesuada
164
        // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
165
        // +      input by: Brett Zamir (http://brett-zamir.me)
166
        // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
167
        // *     example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
168
        // *     returns 1: 'Kevin van Zonneveld'
169
        // mozilla has this native
170
        // - but breaks in 2.0.0.12!
171
        //if (typeof this.global['atob'] == 'function') {
172
        //    return atob(data);
173
        //}
174
            var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
175
                o1,
176
                o2,
177
                o3,
178
                h1,
179
                h2,
180
                h3,
181
                h4,
182
                bits,
183
                i = 0,
184
                ac = 0,
185
                dec = "",
186
                tmp_arr = [];
187
188
            if (!data) {
189
                return data;
190
            }
191
192
            data += '';
193
194
            do { // unpack four hexets into three octets using index points in b64
195
                h1 = b64.indexOf(data.charAt(i++));
196
                h2 = b64.indexOf(data.charAt(i++));
197
                h3 = b64.indexOf(data.charAt(i++));
198
                h4 = b64.indexOf(data.charAt(i++));
199
200
                bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
201
202
                o1 = bits >> 16 & 0xff;
203
                o2 = bits >> 8 & 0xff;
204
                o3 = bits & 0xff;
205
206
                if (h3 === 64) {
207
                    tmp_arr[ac++] = String.fromCharCode(o1);
208
                } else if (h4 === 64) {
209
                    tmp_arr[ac++] = String.fromCharCode(o1, o2);
210
                } else {
211
                    tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
212
                }
213
            } while (i < data.length);
214
            dec = tmp_arr.join('');
215
            return dec;
216
        };
217
    }
218
219
    var getObjectLength = typeof Object.keys === 'function' ?
220
                function (object) {
221
                    return Object.keys(object).length;
222
                } :
223
                function (object) {
224
                    var i = 0, e;
225
                    for (e in object) {
226
                        if (object.hasOwnProperty(e)) {
227
                            i++;
228
                        }
229
                    }
230
                    return i;
231
                };
232
233
/**
234
PubSub implementation
235
236
@class
237
@name PubSub
238
*/
239
        global.PubSub = function (context) {
240
            /**  @preserve
241
            -----------------------------------------------------------------------------------------------
242
            JavaScript PubSub library
243
            2012 (c) [email protected]
244
            based on Peter Higgins ([email protected])
245
            Loosely based on Dojo publish/subscribe API, limited in scope. Rewritten blindly.
246
            Original is (c) Dojo Foundation 2004-2010. Released under either AFL or new BSD, see:
247
            http://dojofoundation.org/license for more information.
248
            -----------------------------------------------------------------------------------------------
249
            */
250
            /**
251
            @private
252
            @fieldOf PubSub
253
            */
254
            this.topics = {};
255
            /**
256
            Stores what will be `this` within the callback functions.
257
258
            @private
259
            @fieldOf PubSub#
260
            */
261
            this.context = context;
262
            /**
263
            Allows caller to emit an event and pass arguments to event listeners.
264
            @public
265
            @function
266
            @param topic {String} Name of the channel on which to voice this event
267
            @param args Any number of arguments you want to pass to the listeners of this event.
268
            @methodOf PubSub#
269
            @name publish
270
            */
271
            this.publish = function (topic, args) {
272
                if (this.topics[topic]) {
273
                    var currentTopic = this.topics[topic],
274
                        toremove = [],
275
                        fn,
276
                        i,
277
                        l,
278
                        pair,
279
                        emptyFunc = function () {};
280
                    args = Array.prototype.slice.call(arguments, 1);
281
                    for (i = 0, l = currentTopic.length; i < l; i++) {
282
                        pair = currentTopic[i]; // this is a [function, once_flag] array
283
                        fn = pair[0];
284
                        if (pair[1]) { /* 'run once' flag set */
285
                            pair[0] = emptyFunc;
286
                            toremove.push(i);
287
                        }
288
                        fn.apply(this.context, args);
289
                    }
290
                    for (i = 0, l = toremove.length; i < l; i++) {
291
                        currentTopic.splice(toremove[i], 1);
292
                    }
293
                }
294
            };
295
            /**
296
            Allows listener code to subscribe to channel and be called when data is available
297
            @public
298
            @function
299
            @param topic {String} Name of the channel on which to voice this event
300
            @param callback {Function} Executable (function pointer) that will be ran when event is voiced on this channel.
301
            @param once {Boolean} (optional. False by default) Flag indicating if the function is to be triggered only once.
302
            @returns {Object} A token object that cen be used for unsubscribing.
303
            @methodOf PubSub#
304
            @name subscribe
305
            */
306
            this.subscribe = function (topic, callback, once) {
307
                if (!this.topics[topic]) {
308
                    this.topics[topic] = [[callback, once]];
309
                } else {
310
                    this.topics[topic].push([callback, once]);
311
                }
312
                return {
313
                    "topic": topic,
314
                    "callback": callback
315
                };
316
            };
317
            /**
318
            Allows listener code to unsubscribe from a channel
319
            @public
320
            @function
321
            @param token {Object} A token object that was returned by `subscribe` method
322
            @methodOf PubSub#
323
            @name unsubscribe
324
            */
325
            this.unsubscribe = function (token) {
326
                if (this.topics[token.topic]) {
327
                    var currentTopic = this.topics[token.topic], i, l;
328
329
                    for (i = 0, l = currentTopic.length; i < l; i++) {
330
                        if (currentTopic[i][0] === token.callback) {
331
                            currentTopic.splice(i, 1);
332
                        }
333
                    }
334
                }
335
            };
336
        };
337
338
339
/**
340
@constructor
341
@private
342
*/
343
    function jsPDF(orientation, unit, format, compressPdf) { /** String orientation, String unit, String format, Boolean compressed */
344
        var options = {};
345
346
        if (typeof orientation === 'object') {
347
            options = orientation;
348
349
            orientation = options.orientation;
350
            unit        = options.unit || unit;
351
            format      = options.format || format;
352
            compressPdf = options.compress || options.compressPdf || compressPdf;
353
        }
354
355
        // Default parameter values
356
        if (typeof orientation === 'undefined') {
357
            orientation = 'p';
358
        } else {
359
            orientation = orientation.toString().toLowerCase();
360
        }
361
        if (typeof unit === 'undefined') { unit = 'mm'; }
362
        if (typeof format === 'undefined') { format = 'a4'; }
363
        if (typeof compressPdf === 'undefined' && typeof zpipe === 'undefined') { compressPdf = false; }
364
365
        var format_as_string = format.toString().toLowerCase(),
366
            content = [],
367
            content_length = 0,
368
            compress = compressPdf,
369
            pdfVersion = '1.3', // PDF Version
370
            pageFormats = { // Size in pt of various paper formats
371
                'a0': [2383.94, 3370.39],
372
                'a1': [1683.78, 2383.94],
373
                'a2': [1190.55, 1683.78],
374
                'a3': [841.89,  1190.55],
375
                'a4': [595.28,  841.89],
376
                'a5': [419.53,  595.28],
377
                'a6': [297.64,  419.53],
378
                'a7': [209.76,  297.64],
379
                'a8': [147.4 ,  209.76],
380
                'a9': [104.88,  147.4],
381
                'a10': [73.7,  104.88],
382
                'b0': [2834.65, 4008.19],
383
                'b1': [2004.09, 2834.65],
384
                'b2': [1417.32, 2004.09],
385
                'b3': [1000.63, 1417.32],
386
                'b4': [708.66,  1000.63],
387
                'b5': [498.9,  708.66],
388
                'b6': [354.33,  498.9],
389
                'b7': [249.45,  354.33],
390
                'b8': [175.75,  249.45],
391
                'b9': [124.72,  175.75],
392
                'b10': [87.87,  124.72],
393
                'c0': [2599.37, 3676.54],
394
                'c1': [1836.85, 2599.37],
395
                'c2': [1298.27, 1836.85],
396
                'c3': [918.43,  1298.27],
397
                'c4': [649.13,  918.43],
398
                'c5': [459.21,  649.13],
399
                'c6': [323.15,  459.21],
400
                'c7': [229.61,  323.15],
401
                'c8': [161.57,  229.61],
402
                'c9': [113.39,  161.57],
403
                'c10': [79.37,   113.39],
404
                'letter': [612, 792],
405
                'government-letter': [576, 756],
406
                'legal': [612, 1008],
407
                'junior-legal': [576, 360],
408
                'ledger': [1224, 792],
409
                'tabloid': [792, 1224]
410
            },
411
            textColor = options.textColor || '0 g',
412
            drawColor = options.drawColor || '0 G',
413
            page = 0,
414
            pages = [],
415
            objectNumber = 2, // 'n' Current object number
416
            outToPages = !!options.outToPages, // switches where out() prints. outToPages true = push to pages obj. outToPages false = doc builder content
417
            offsets = [], // List of offsets. Activated and reset by buildDocument(). Pupulated by various calls buildDocument makes.
418
            fonts = {}, // collection of font objects, where key is fontKey - a dynamically created label for a given font.
419
            fontmap = {}, // mapping structure fontName > fontStyle > font key - performance layer. See addFont()
420
            activeFontSize = options.fontSize || 16,
421
            activeFontKey, // will be string representing the KEY of the font as combination of fontName + fontStyle
422
            lineWidth = options.lineWidth || 0.200025, // 2mm
423
            lineHeightProportion = options.lineHeight || 1.15,
424
            pageHeight,
425
            pageWidth,
426
            k, // Scale factor
427
            documentProperties = {'title': '', 'subject': '', 'author': '', 'keywords': '', 'creator': ''},
428
            lineCapID = 0,
429
            lineJoinID = 0,
430
            API = {},
431
            events = new PubSub(API),
0 ignored issues
show
Bug introduced by
The variable PubSub seems to be never declared. If this is a global, consider adding a /** global: PubSub */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
432
            tmp,
433
            plugin,
434
            /////////////////////
435
            // Private functions
436
            /////////////////////
437
            // simplified (speedier) replacement for sprintf's %.2f conversion
438
            f2 = function (number) {
439
                return number.toFixed(2);
440
            },
441
            // simplified (speedier) replacement for sprintf's %.3f conversion
442
            f3 = function (number) {
443
                return number.toFixed(3);
444
            },
445
            // simplified (speedier) replacement for sprintf's %02d
446
            padd2 = function (number) {
447
                var n = (number).toFixed(0);
448
                if (number < 10) {
449
                    return '0' + n;
450
                } else {
451
                    return n;
452
                }
453
            },
454
            // simplified (speedier) replacement for sprintf's %02d
455
            padd10 = function (number) {
456
                var n = (number).toFixed(0);
457
                if (n.length < 10) {
458
                    return new Array( 11 - n.length ).join('0') + n;
459
                } else {
460
                    return n;
461
                }
462
            },
463
            out = function (string) {
464
                if (outToPages) { /* set by beginPage */
465
                    pages[page].push(string);
466
                } else {
467
                    content.push(string);
468
                    content_length += string.length + 1; // +1 is for '\n' that will be used to join contents of content
469
                }
470
            },
471
            newObject = function () {
472
                // Begin a new object
473
                objectNumber++;
474
                offsets[objectNumber] = content_length;
475
                out(objectNumber + ' 0 obj');
476
                return objectNumber;
477
            },
478
            putStream = function (str) {
479
                out('stream');
480
                out(str);
481
                out('endstream');
482
            },
483
            wPt,
484
            hPt,
485
            kids,
486
            i,
0 ignored issues
show
Unused Code introduced by
The variable i seems to be never used. Consider removing it.
Loading history...
487
            putPages = function () {
488
                wPt = pageWidth * k;
489
                hPt = pageHeight * k;
490
491
                // outToPages = false as set in endDocument(). out() writes to content.
492
493
                var n, p, arr, uint, i, deflater, adler32;
0 ignored issues
show
Unused Code introduced by
The variable uint seems to be never used. Consider removing it.
Loading history...
494
                for (n = 1; n <= page; n++) {
495
                    newObject();
496
                    out('<</Type /Page');
497
                    out('/Parent 1 0 R');
498
                    out('/Resources 2 0 R');
499
                    out('/Contents ' + (objectNumber + 1) + ' 0 R>>');
500
                    out('endobj');
501
502
                    // Page content
503
                    p = pages[n].join('\n');
504
                    newObject();
505
                    if (compress) {
506
                        arr = [];
507
                        for (i = 0; i < p.length; ++i) {
508
                            arr[i] = p.charCodeAt(i);
509
                        }
510
                        adler32 = adler32cs.from(p);
511
                        deflater = new Deflater(6);
512
                        deflater.append(new Uint8Array(arr));
513
                        p = deflater.flush();
514
                        arr = [new Uint8Array([120, 156]), new Uint8Array(p),
515
                               new Uint8Array([adler32 & 0xFF, (adler32 >> 8) & 0xFF, (adler32 >> 16) & 0xFF, (adler32 >> 24) & 0xFF])];
516
                        p = '';
517
                        for (i in arr) {
518
                            if (arr.hasOwnProperty(i)) {
519
                                p += String.fromCharCode.apply(null, arr[i]);
520
                            }
521
                        }
522
                        out('<</Length ' + p.length  + ' /Filter [/FlateDecode]>>');
523
                    } else {
524
                        out('<</Length ' + p.length  + '>>');
525
                    }
526
                    putStream(p);
527
                    out('endobj');
528
                }
529
                offsets[1] = content_length;
530
                out('1 0 obj');
531
                out('<</Type /Pages');
532
                kids = '/Kids [';
533
                for (i = 0; i < page; i++) {
534
                    kids += (3 + 2 * i) + ' 0 R ';
0 ignored issues
show
Bug introduced by
The variable kids is changed as part of the for loop for example by 3 + 2 * i + " 0 R " on line 534. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
535
                }
536
                out(kids + ']');
537
                out('/Count ' + page);
538
                out('/MediaBox [0 0 ' + f2(wPt) + ' ' + f2(hPt) + ']');
539
                out('>>');
540
                out('endobj');
541
            },
542
            putFont = function (font) {
543
                font.objectNumber = newObject();
544
                out('<</BaseFont/' + font.PostScriptName + '/Type/Font');
545
                if (typeof font.encoding === 'string') {
546
                    out('/Encoding/' + font.encoding);
547
                }
548
                out('/Subtype/Type1>>');
549
                out('endobj');
550
            },
551
            putFonts = function () {
552
                var fontKey;
553
                for (fontKey in fonts) {
554
                    if (fonts.hasOwnProperty(fontKey)) {
555
                        putFont(fonts[fontKey]);
556
                    }
557
                }
558
            },
559
            putXobjectDict = function () {
560
                // Loop through images, or other data objects
561
                events.publish('putXobjectDict');
562
            },
563
            putResourceDictionary = function () {
564
                out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
565
                out('/Font <<');
566
                // Do this for each font, the '1' bit is the index of the font
567
                var fontKey;
568
                for (fontKey in fonts) {
569
                    if (fonts.hasOwnProperty(fontKey)) {
570
                        out('/' + fontKey + ' ' + fonts[fontKey].objectNumber + ' 0 R');
571
                    }
572
                }
573
                out('>>');
574
                out('/XObject <<');
575
                putXobjectDict();
576
                out('>>');
577
            },
578
            putResources = function () {
579
                putFonts();
580
                events.publish('putResources');
581
                // Resource dictionary
582
                offsets[2] = content_length;
583
                out('2 0 obj');
584
                out('<<');
585
                putResourceDictionary();
586
                out('>>');
587
                out('endobj');
588
                events.publish('postPutResources');
589
            },
590
            addToFontDictionary = function (fontKey, fontName, fontStyle) {
591
                // this is mapping structure for quick font key lookup.
592
                // returns the KEY of the font (ex: "F1") for a given pair of font name and type (ex: "Arial". "Italic")
593
                var undef;
594
                if (fontmap[fontName] === undef) {
0 ignored issues
show
Bug introduced by
The variable undef seems to be never initialized.
Loading history...
595
                    fontmap[fontName] = {}; // fontStyle is a var interpreted and converted to appropriate string. don't wrap in quotes.
596
                }
597
                fontmap[fontName][fontStyle] = fontKey;
598
            },
599
            /**
600
            FontObject describes a particular font as member of an instnace of jsPDF
601
602
            It's a collection of properties like 'id' (to be used in PDF stream),
603
            'fontName' (font's family name), 'fontStyle' (font's style variant label)
604
605
            @class
606
            @public
607
            @property id {String} PDF-document-instance-specific label assinged to the font.
608
            @property PostScriptName {String} PDF specification full name for the font
609
            @property encoding {Object} Encoding_name-to-Font_metrics_object mapping.
610
            @name FontObject
611
            */
612
            FontObject = {},
0 ignored issues
show
Unused Code introduced by
The variable FontObject seems to be never used. Consider removing it.
Loading history...
613
            addFont = function (PostScriptName, fontName, fontStyle, encoding) {
614
                var fontKey = 'F' + (getObjectLength(fonts) + 1).toString(10),
615
                    // This is FontObject
616
                    font = fonts[fontKey] = {
617
                        'id': fontKey,
618
                        // , 'objectNumber':   will be set by putFont()
619
                        'PostScriptName': PostScriptName,
620
                        'fontName': fontName,
621
                        'fontStyle': fontStyle,
622
                        'encoding': encoding,
623
                        'metadata': {}
624
                    };
625
626
                addToFontDictionary(fontKey, fontName, fontStyle);
627
628
                events.publish('addFont', font);
629
630
                return fontKey;
631
            },
632
            addFonts = function () {
633
634
                var HELVETICA = "helvetica",
635
                    TIMES = "times",
636
                    COURIER = "courier",
637
                    NORMAL = "normal",
638
                    BOLD = "bold",
639
                    ITALIC = "italic",
640
                    BOLD_ITALIC = "bolditalic",
641
                    encoding = 'StandardEncoding',
642
                    standardFonts = [
643
                        ['Helvetica', HELVETICA, NORMAL],
644
                        ['Helvetica-Bold', HELVETICA, BOLD],
645
                        ['Helvetica-Oblique', HELVETICA, ITALIC],
646
                        ['Helvetica-BoldOblique', HELVETICA, BOLD_ITALIC],
647
                        ['Courier', COURIER, NORMAL],
648
                        ['Courier-Bold', COURIER, BOLD],
649
                        ['Courier-Oblique', COURIER, ITALIC],
650
                        ['Courier-BoldOblique', COURIER, BOLD_ITALIC],
651
                        ['Times-Roman', TIMES, NORMAL],
652
                        ['Times-Bold', TIMES, BOLD],
653
                        ['Times-Italic', TIMES, ITALIC],
654
                        ['Times-BoldItalic', TIMES, BOLD_ITALIC]
655
                    ],
656
                    i,
657
                    l,
658
                    fontKey,
659
                    parts;
660
                for (i = 0, l = standardFonts.length; i < l; i++) {
661
                    fontKey = addFont(
662
                        standardFonts[i][0],
663
                        standardFonts[i][1],
664
                        standardFonts[i][2],
665
                        encoding
666
                    );
667
668
                    // adding aliases for standard fonts, this time matching the capitalization
669
                    parts = standardFonts[i][0].split('-');
670
                    addToFontDictionary(fontKey, parts[0], parts[1] || '');
671
                }
672
673
                events.publish('addFonts', {'fonts': fonts, 'dictionary': fontmap});
674
            },
675
            /**
676
677
            @public
678
            @function
679
            @param text {String}
680
            @param flags {Object} Encoding flags.
681
            @returns {String} Encoded string
682
            */
683
            to8bitStream = function (text, flags) {
684
                /* PDF 1.3 spec:
685
                "For text strings encoded in Unicode, the first two bytes must be 254 followed by
686
                255, representing the Unicode byte order marker, U+FEFF. (This sequence conflicts
687
                with the PDFDocEncoding character sequence thorn ydieresis, which is unlikely
688
                to be a meaningful beginning of a word or phrase.) The remainder of the
689
                string consists of Unicode character codes, according to the UTF-16 encoding
690
                specified in the Unicode standard, version 2.0. Commonly used Unicode values
691
                are represented as 2 bytes per character, with the high-order byte appearing first
692
                in the string."
693
694
                In other words, if there are chars in a string with char code above 255, we
695
                recode the string to UCS2 BE - string doubles in length and BOM is prepended.
696
697
                HOWEVER!
698
                Actual *content* (body) text (as opposed to strings used in document properties etc)
699
                does NOT expect BOM. There, it is treated as a literal GID (Glyph ID)
700
701
                Because of Adobe's focus on "you subset your fonts!" you are not supposed to have
702
                a font that maps directly Unicode (UCS2 / UTF16BE) code to font GID, but you could
703
                fudge it with "Identity-H" encoding and custom CIDtoGID map that mimics Unicode
704
                code page. There, however, all characters in the stream are treated as GIDs,
705
                including BOM, which is the reason we need to skip BOM in content text (i.e. that
706
                that is tied to a font).
707
708
                To signal this "special" PDFEscape / to8bitStream handling mode,
709
                API.text() function sets (unless you overwrite it with manual values
710
                given to API.text(.., flags) )
711
                    flags.autoencode = true
712
                    flags.noBOM = true
713
714
                */
715
716
                /*
717
                `flags` properties relied upon:
718
                .sourceEncoding = string with encoding label.
719
                    "Unicode" by default. = encoding of the incoming text.
720
                    pass some non-existing encoding name
721
                    (ex: 'Do not touch my strings! I know what I am doing.')
722
                    to make encoding code skip the encoding step.
723
                .outputEncoding = Either valid PDF encoding name
724
                    (must be supported by jsPDF font metrics, otherwise no encoding)
725
                    or a JS object, where key = sourceCharCode, value = outputCharCode
726
                    missing keys will be treated as: sourceCharCode === outputCharCode
727
                .noBOM
728
                    See comment higher above for explanation for why this is important
729
                .autoencode
730
                    See comment higher above for explanation for why this is important
731
                */
732
733
                var i, l, undef, sourceEncoding, encodingBlock, outputEncoding, newtext, isUnicode, ch, bch;
734
735
                if (flags === undef) {
0 ignored issues
show
Bug introduced by
The variable undef seems to be never initialized.
Loading history...
736
                    flags = {};
737
                }
738
739
                sourceEncoding = flags.sourceEncoding ? sourceEncoding : 'Unicode';
0 ignored issues
show
Bug introduced by
The variable sourceEncoding seems to be never initialized.
Loading history...
740
741
                outputEncoding = flags.outputEncoding;
742
743
                // This 'encoding' section relies on font metrics format
744
                // attached to font objects by, among others,
745
                // "Willow Systems' standard_font_metrics plugin"
746
                // see jspdf.plugin.standard_font_metrics.js for format
747
                // of the font.metadata.encoding Object.
748
                // It should be something like
749
                //   .encoding = {'codePages':['WinANSI....'], 'WinANSI...':{code:code, ...}}
750
                //   .widths = {0:width, code:width, ..., 'fof':divisor}
751
                //   .kerning = {code:{previous_char_code:shift, ..., 'fof':-divisor},...}
752
                if ((flags.autoencode || outputEncoding) &&
753
                        fonts[activeFontKey].metadata &&
754
                        fonts[activeFontKey].metadata[sourceEncoding] &&
755
                        fonts[activeFontKey].metadata[sourceEncoding].encoding
756
                        ) {
757
                    encodingBlock = fonts[activeFontKey].metadata[sourceEncoding].encoding;
758
759
                    // each font has default encoding. Some have it clearly defined.
760
                    if (!outputEncoding && fonts[activeFontKey].encoding) {
761
                        outputEncoding = fonts[activeFontKey].encoding;
762
                    }
763
764
                    // Hmmm, the above did not work? Let's try again, in different place.
765
                    if (!outputEncoding && encodingBlock.codePages) {
766
                        outputEncoding = encodingBlock.codePages[0]; // let's say, first one is the default
767
                    }
768
769
                    if (typeof outputEncoding === 'string') {
770
                        outputEncoding = encodingBlock[outputEncoding];
771
                    }
772
                    // we want output encoding to be a JS Object, where
773
                    // key = sourceEncoding's character code and
774
                    // value = outputEncoding's character code.
775
                    if (outputEncoding) {
776
                        isUnicode = false;
777
                        newtext = [];
778
                        for (i = 0, l = text.length; i < l; i++) {
779
                            ch = outputEncoding[text.charCodeAt(i)];
780
                            if (ch) {
781
                                newtext.push(
782
                                    String.fromCharCode(ch)
783
                                );
784
                            } else {
785
                                newtext.push(
786
                                    text[i]
787
                                );
788
                            }
789
790
                            // since we are looping over chars anyway, might as well
791
                            // check for residual unicodeness
792
                            if (newtext[i].charCodeAt(0) >> 8) { /* more than 255 */
793
                                isUnicode = true;
794
                            }
795
                        }
796
                        text = newtext.join('');
797
                    }
798
                }
799
800
                i = text.length;
801
                // isUnicode may be set to false above. Hence the triple-equal to undefined
802
                while (isUnicode === undef && i !== 0) {
0 ignored issues
show
Bug introduced by
The variable isUnicode seems to not be initialized for all possible execution paths.
Loading history...
803
                    if (text.charCodeAt(i - 1) >> 8) { /* more than 255 */
804
                        isUnicode = true;
805
                    }
806
                    i--;
807
                }
808
                if (!isUnicode) {
809
                    return text;
810
                } else {
811
                    newtext = flags.noBOM ? [] : [254, 255];
812
                    for (i = 0, l = text.length; i < l; i++) {
813
                        ch = text.charCodeAt(i);
814
                        bch = ch >> 8; // divide by 256
815
                        if (bch >> 8) { /* something left after dividing by 256 second time */
816
                            throw new Error("Character at position " + i.toString(10) + " of string '" + text + "' exceeds 16bits. Cannot be encoded into UCS-2 BE");
817
                        }
818
                        newtext.push(bch);
819
                        newtext.push(ch - (bch << 8));
820
                    }
821
                    return String.fromCharCode.apply(undef, newtext);
822
                }
823
            },
824
            // Replace '/', '(', and ')' with pdf-safe versions
825
            pdfEscape = function (text, flags) {
826
                // doing to8bitStream does NOT make this PDF display unicode text. For that
827
                // we also need to reference a unicode font and embed it - royal pain in the rear.
828
829
                // There is still a benefit to to8bitStream - PDF simply cannot handle 16bit chars,
830
                // which JavaScript Strings are happy to provide. So, while we still cannot display
831
                // 2-byte characters property, at least CONDITIONALLY converting (entire string containing)
832
                // 16bit chars to (USC-2-BE) 2-bytes per char + BOM streams we ensure that entire PDF
833
                // is still parseable.
834
                // This will allow immediate support for unicode in document properties strings.
835
                return to8bitStream(text, flags).replace(/\\/g, '\\\\').replace(/\(/g, '\\(').replace(/\)/g, '\\)');
836
            },
837
            putInfo = function () {
838
                out('/Producer (jsPDF ' + jsPDF.version + ')');
839
                if (documentProperties.title) {
840
                    out('/Title (' + pdfEscape(documentProperties.title) + ')');
841
                }
842
                if (documentProperties.subject) {
843
                    out('/Subject (' + pdfEscape(documentProperties.subject) + ')');
844
                }
845
                if (documentProperties.author) {
846
                    out('/Author (' + pdfEscape(documentProperties.author) + ')');
847
                }
848
                if (documentProperties.keywords) {
849
                    out('/Keywords (' + pdfEscape(documentProperties.keywords) + ')');
850
                }
851
                if (documentProperties.creator) {
852
                    out('/Creator (' + pdfEscape(documentProperties.creator) + ')');
853
                }
854
                var created = new Date();
855
                out('/CreationDate (D:' +
856
                    [
857
                        created.getFullYear(),
858
                        padd2(created.getMonth() + 1),
859
                        padd2(created.getDate()),
860
                        padd2(created.getHours()),
861
                        padd2(created.getMinutes()),
862
                        padd2(created.getSeconds())
863
                    ].join('') +
864
                    ')'
865
                    );
866
            },
867
            putCatalog = function () {
868
                out('/Type /Catalog');
869
                out('/Pages 1 0 R');
870
                // @TODO: Add zoom and layout modes
871
                out('/OpenAction [3 0 R /FitH null]');
872
                out('/PageLayout /OneColumn');
873
                events.publish('putCatalog');
874
            },
875
            putTrailer = function () {
876
                out('/Size ' + (objectNumber + 1));
877
                out('/Root ' + objectNumber + ' 0 R');
878
                out('/Info ' + (objectNumber - 1) + ' 0 R');
879
            },
880
            beginPage = function () {
881
                page++;
882
                // Do dimension stuff
883
                outToPages = true;
884
                pages[page] = [];
885
            },
886
            _addPage = function () {
887
                beginPage();
888
                // Set line width
889
                out(f2(lineWidth * k) + ' w');
890
                // Set draw color
891
                out(drawColor);
892
                // resurrecting non-default line caps, joins
893
                if (lineCapID !== 0) {
894
                    out(lineCapID.toString(10) + ' J');
895
                }
896
                if (lineJoinID !== 0) {
897
                    out(lineJoinID.toString(10) + ' j');
898
                }
899
                events.publish('addPage', {'pageNumber': page});
900
            },
901
            /**
902
            Returns a document-specific font key - a label assigned to a
903
            font name + font type combination at the time the font was added
904
            to the font inventory.
905
906
            Font key is used as label for the desired font for a block of text
907
            to be added to the PDF document stream.
908
            @private
909
            @function
910
            @param fontName {String} can be undefined on "falthy" to indicate "use current"
911
            @param fontStyle {String} can be undefined on "falthy" to indicate "use current"
912
            @returns {String} Font key.
913
            */
914
            getFont = function (fontName, fontStyle) {
915
                var key, undef;
916
917
                if (fontName === undef) {
0 ignored issues
show
Bug introduced by
The variable undef seems to be never initialized.
Loading history...
918
                    fontName = fonts[activeFontKey].fontName;
919
                }
920
                if (fontStyle === undef) {
921
                    fontStyle = fonts[activeFontKey].fontStyle;
922
                }
923
924
                try {
925
                    key = fontmap[fontName][fontStyle]; // returns a string like 'F3' - the KEY corresponding tot he font + type combination.
926
                } catch (e) {
927
                    key = undef;
928
                }
929
                if (!key) {
930
                    throw new Error("Unable to look up font label for font '" + fontName + "', '" + fontStyle + "'. Refer to getFontList() for available fonts.");
931
                }
932
933
                return key;
934
            },
935
            buildDocument = function () {
936
937
                outToPages = false; // switches out() to content
938
                objectNumber = 2;
939
                content = [];
940
                offsets = [];
941
942
                // putHeader()
943
                out('%PDF-' + pdfVersion);
944
945
                putPages();
946
947
                putResources();
948
949
                // Info
950
                newObject();
951
                out('<<');
952
                putInfo();
953
                out('>>');
954
                out('endobj');
955
956
                // Catalog
957
                newObject();
958
                out('<<');
959
                putCatalog();
960
                out('>>');
961
                out('endobj');
962
963
                // Cross-ref
964
                var o = content_length, i;
965
                out('xref');
966
                out('0 ' + (objectNumber + 1));
967
                out('0000000000 65535 f ');
968
                for (i = 1; i <= objectNumber; i++) {
969
                    out(padd10(offsets[i]) + ' 00000 n ');
970
                }
971
                // Trailer
972
                out('trailer');
973
                out('<<');
974
                putTrailer();
975
                out('>>');
976
                out('startxref');
977
                out(o);
978
                out('%%EOF');
979
980
                outToPages = true;
981
982
                return content.join('\n');
983
            },
984
            getStyle = function (style) {
985
                // see Path-Painting Operators of PDF spec
986
                var op = 'S'; // stroke
987
                if (style === 'F') {
988
                    op = 'f'; // fill
989
                } else if (style === 'FD' || style === 'DF') {
990
                    op = 'B'; // both
991
                }
992
                return op;
993
            },
994
            getBlob = function () {
995
                var data, length, array, i, blob;
996
                data = buildDocument();
997
998
                // Need to add the file to BlobBuilder as a Uint8Array
999
                length = data.length;
1000
                array = new Uint8Array(new ArrayBuffer(length));
1001
1002
                for (i = 0; i < length; i++) {
1003
                    array[i] = data.charCodeAt(i);
1004
                }
1005
1006
                blob = new Blob([array], {type: "application/pdf"});
1007
                return blob;
1008
            },
1009
            /**
1010
            Generates the PDF document.
1011
            Possible values:
1012
                datauristring (alias dataurlstring) - Data-Url-formatted data returned as string.
1013
                datauri (alias datauri) - Data-Url-formatted data pushed into current global's location (effectively reloading the global with contents of the PDF).
1014
1015
            If `type` argument is undefined, output is raw body of resulting PDF returned as a string.
1016
1017
            @param {String} type A string identifying one of the possible output types.
1018
            @param {Object} options An object providing some additional signalling to PDF generator.
1019
            @function
1020
            @returns {jsPDF}
1021
            @methodOf jsPDF#
1022
            @name output
1023
            */
1024
            output = function (type, options) {
1025
                var undef;
0 ignored issues
show
Unused Code introduced by
The variable undef seems to be never used. Consider removing it.
Loading history...
1026
                switch (type) {
1027
                case undef:
0 ignored issues
show
Bug introduced by
The variable undef seems to be never declared. If this is a global, consider adding a /** global: undef */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1028
                    return buildDocument();
1029
                case 'save':
1030
                    if (navigator.getUserMedia) {
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1031
                        if (global.URL === undefined) {
1032
                            return API.output('dataurlnewwindow');
1033
                        } else if (global.URL.createObjectURL === undefined) {
1034
                            return API.output('dataurlnewwindow');
1035
                        }
1036
                    }
1037
                    saveAs(getBlob(), options);
1038
                    break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
1039
                case 'blob':
1040
                    return getBlob();
1041
                case 'datauristring':
1042
                case 'dataurlstring':
1043
                    return 'data:application/pdf;base64,' + btoa(buildDocument());
1044
                case 'datauri':
1045
                case 'dataurl':
1046
                    document.location.href = 'data:application/pdf;base64,' + btoa(buildDocument());
1047
                    break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
1048
                case 'dataurlnewwindow':
1049
                    global.open('data:application/pdf;base64,' + btoa(buildDocument()));
1050
                    break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
1051
                default:
1052
                    throw new Error('Output type "' + type + '" is not supported.');
1053
                }
1054
                // @TODO: Add different output options
1055
            };
1056
1057
        if (unit === 'pt') {
1058
            k = 1;
1059
        } else if (unit === 'mm') {
1060
            k = 72 / 25.4;
1061
        } else if (unit === 'cm') {
1062
            k = 72 / 2.54;
1063
        } else if (unit === 'in') {
1064
            k = 72;
1065
        } else {
1066
            throw ('Invalid unit: ' + unit);
1067
        }
1068
1069
        // Dimensions are stored as user units and converted to points on output
1070
        if (pageFormats.hasOwnProperty(format_as_string)) {
1071
            pageHeight = pageFormats[format_as_string][1] / k;
1072
            pageWidth = pageFormats[format_as_string][0] / k;
1073
        } else {
1074
            try {
1075
                pageHeight = format[1];
1076
                pageWidth = format[0];
1077
            } catch (err) {
1078
                throw ('Invalid format: ' + format);
1079
            }
1080
        }
1081
1082
        if (orientation === 'p' || orientation === 'portrait') {
1083
            orientation = 'p';
0 ignored issues
show
Unused Code introduced by
The assignment to variable orientation seems to be never used. Consider removing it.
Loading history...
1084
            if (pageWidth > pageHeight) {
1085
                tmp = pageWidth;
1086
                pageWidth = pageHeight;
1087
                pageHeight = tmp;
1088
            }
1089
        } else if (orientation === 'l' || orientation === 'landscape') {
1090
            orientation = 'l';
1091
            if (pageHeight > pageWidth) {
1092
                tmp = pageWidth;
1093
                pageWidth = pageHeight;
1094
                pageHeight = tmp;
1095
            }
1096
        } else {
1097
            throw ('Invalid orientation: ' + orientation);
1098
        }
1099
1100
1101
1102
        //---------------------------------------
1103
        // Public API
1104
1105
        /*
1106
        Object exposing internal API to plugins
1107
        @public
1108
        */
1109
        API.internal = {
1110
            'pdfEscape': pdfEscape,
1111
            'getStyle': getStyle,
1112
            /**
1113
            Returns {FontObject} describing a particular font.
1114
            @public
1115
            @function
1116
            @param fontName {String} (Optional) Font's family name
0 ignored issues
show
Documentation introduced by
The parameter fontName does not exist. Did you maybe forget to remove this comment?
Loading history...
1117
            @param fontStyle {String} (Optional) Font's style variation name (Example:"Italic")
0 ignored issues
show
Documentation introduced by
The parameter fontStyle does not exist. Did you maybe forget to remove this comment?
Loading history...
1118
            @returns {FontObject}
1119
            */
1120
            'getFont': function () { return fonts[getFont.apply(API, arguments)]; },
1121
            'getFontSize': function () { return activeFontSize;    },
1122
            'getLineHeight': function () { return activeFontSize * lineHeightProportion;    },
1123
            'btoa': btoa,
1124
            'write': function (string1, string2, string3, etc) {
0 ignored issues
show
Unused Code introduced by
The parameter string2 is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter string3 is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter etc is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1125
                out(
1126
                    arguments.length === 1 ? string1 : Array.prototype.join.call(arguments, ' ')
1127
                );
1128
            },
1129
            'getCoordinateString': function (value) {
1130
                return f2(value * k);
1131
            },
1132
            'getVerticalCoordinateString': function (value) {
1133
                return f2((pageHeight - value) * k);
1134
            },
1135
            'collections': {},
1136
            'newObject': newObject,
1137
            'putStream': putStream,
1138
            'events': events,
1139
            // ratio that you use in multiplication of a given "size" number to arrive to 'point'
1140
            // units of measurement.
1141
            // scaleFactor is set at initialization of the document and calculated against the stated
1142
            // default measurement units for the document.
1143
            // If default is "mm", k is the number that will turn number in 'mm' into 'points' number.
1144
            // through multiplication.
1145
            'scaleFactor': k,
1146
            'pageSize': {'width': pageWidth, 'height': pageHeight},
1147
            'output': function (type, options) {
1148
                return output(type, options);
1149
            },
1150
            'getNumberOfPages': function () {return pages.length - 1; },
1151
            'pages': pages
1152
        };
1153
1154
        /**
1155
        Adds (and transfers the focus to) new page to the PDF document.
1156
        @function
1157
        @returns {jsPDF}
1158
1159
        @methodOf jsPDF#
1160
        @name addPage
1161
         */
1162
        API.addPage = function () {
1163
            _addPage();
1164
            return this;
1165
        };
1166
1167
        /**
1168
        Adds text to page. Supports adding multiline text when 'text' argument is an Array of Strings.
1169
        @function
1170
        @param {String|Array} text String or array of strings to be added to the page. Each line is shifted one line down per font, spacing settings declared before this call.
1171
        @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1172
        @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1173
        @param {Object} flags Collection of settings signalling how the text must be encoded. Defaults are sane. If you think you want to pass some flags, you likely can read the source.
1174
        @returns {jsPDF}
1175
        @methodOf jsPDF#
1176
        @name text
1177
         */
1178
        API.text = function (text, x, y, flags, angle) {
1179
            /**
1180
             * Inserts something like this into PDF
1181
                BT
1182
                /F1 16 Tf  % Font name + size
1183
                16 TL % How many units down for next line in multiline text
1184
                0 g % color
1185
                28.35 813.54 Td % position
1186
                (line one) Tj
1187
                T* (line two) Tj
1188
                T* (line three) Tj
1189
                ET
1190
            */
1191
1192
            // Pre-August-2012 the order of arguments was function(x, y, text, flags)
1193
            // in effort to make all calls have similar signature like
1194
            //   function(data, coordinates... , miscellaneous)
1195
            // this method had its args flipped.
1196
            // code below allows backward compatibility with old arg order.
1197
            if (typeof text === 'number') {
1198
                var tmp = y;
1199
                y = x;
1200
                x = text;
1201
                text = tmp;
1202
            }
1203
1204
            // If there are any newlines in text, we assume
1205
            // the user wanted to print multiple lines, so break the
1206
            // text up into an array.  If the text is already an array,
1207
            // we assume the user knows what they are doing.
1208
            if (typeof text === 'string' && text.match(/[\n\r]/)) {
1209
                text = text.split(/\r\n|\r|\n/g);
1210
            }
1211
            if(typeof flags === 'number') {
1212
                angle = flags;
1213
                flags = null;
1214
            }
1215
            var xtra = '', mode = 'Td';
1216
            if(angle) {
1217
                angle *= (Math.PI / 180);
1218
                var c = Math.cos(angle), s = Math.sin(angle);
1219
                xtra = [f2(c),f2(s),f2(s*-1),f2(c),''].join(" ");
1220
                mode = 'Tm';
1221
            }
1222
            flags = flags || {};
1223
            if(!('noBOM' in flags)) flags.noBOM = true;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
1224
            if(!('autoencode' in flags)) flags.autoencode = true;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
1225
1226
            if (typeof text === 'string') {
1227
                text = pdfEscape(text, flags);
1228
            } else if (text instanceof Array) {  /* Array */
1229
                // we don't want to destroy  original text array, so cloning it
1230
                var sa = text.concat(), da = [], len = sa.length;
1231
                // we do array.join('text that must not be PDFescaped")
1232
                // thus, pdfEscape each component separately
1233
                while(len--) {
1234
                    da.push(pdfEscape( sa.shift(), flags));
1235
                }
1236
                text = da.join(") Tj\nT* (");
1237
            } else {
1238
                throw new Error('Type of text must be string or Array. "' + text + '" is not recognized.');
1239
            }
1240
            // Using "'" ("go next line and render text" mark) would save space but would complicate our rendering code, templates
1241
1242
            // BT .. ET does NOT have default settings for Tf. You must state that explicitely every time for BT .. ET
1243
            // if you want text transformation matrix (+ multiline) to work reliably (which reads sizes of things from font declarations)
1244
            // Thus, there is NO useful, *reliable* concept of "default" font for a page.
1245
            // The fact that "default" (reuse font used before) font worked before in basic cases is an accident
1246
            // - readers dealing smartly with brokenness of jsPDF's markup.
1247
            out(
1248
                'BT\n/' +
1249
                    activeFontKey + ' ' + activeFontSize + ' Tf\n' + // font face, style, size
1250
                    (activeFontSize * lineHeightProportion) + ' TL\n' + // line spacing
1251
                    textColor +
1252
                    '\n' + xtra + f2(x * k) + ' ' + f2((pageHeight - y) * k) + ' ' + mode + '\n(' +
1253
                    text +
1254
                    ') Tj\nET'
1255
            );
1256
            return this;
1257
        };
1258
1259
        API.line = function (x1, y1, x2, y2) {
1260
            out(
1261
                f2(x1 * k) + ' ' + f2((pageHeight - y1) * k) + ' m ' +
1262
                    f2(x2 * k) + ' ' + f2((pageHeight - y2) * k) + ' l S'
1263
            );
1264
            return this;
1265
        };
1266
1267
        /**
1268
        Adds series of curves (straight lines or cubic bezier curves) to canvas, starting at `x`, `y` coordinates.
1269
        All data points in `lines` are relative to last line origin.
1270
        `x`, `y` become x1,y1 for first line / curve in the set.
1271
        For lines you only need to specify [x2, y2] - (ending point) vector against x1, y1 starting point.
1272
        For bezier curves you need to specify [x2,y2,x3,y3,x4,y4] - vectors to control points 1, 2, ending point. All vectors are against the start of the curve - x1,y1.
1273
1274
        @example .lines([[2,2],[-2,2],[1,1,2,2,3,3],[2,1]], 212,110, 10) // line, line, bezier curve, line
1275
        @param {Array} lines Array of *vector* shifts as pairs (lines) or sextets (cubic bezier curves).
1276
        @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1277
        @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1278
        @param {Number} scale (Defaults to [1.0,1.0]) x,y Scaling factor for all vectors. Elements can be any floating number Sub-one makes drawing smaller. Over-one grows the drawing. Negative flips the direction.
1279
        @param {String} style One of 'S' (the default), 'F', 'FD' or 'DF'.  'S' draws just the curve. 'F' fills the region defined by the curves. 'DF' or 'FD' draws the curves and fills the region. 
1280
        @param {Boolean} closed If true, the path is closed with a straight line from the end of the last curve to the starting point. 
1281
        @function
1282
        @returns {jsPDF}
1283
        @methodOf jsPDF#
1284
        @name lines
1285
         */
1286
        API.lines = function (lines, x, y, scale, style, closed) {
1287
            var undef, _first, _second, _third, scalex, scaley, i, l, leg, x2, y2, x3, y3, x4, y4;
1288
1289
            // Pre-August-2012 the order of arguments was function(x, y, lines, scale, style)
1290
            // in effort to make all calls have similar signature like
1291
            //   function(content, coordinateX, coordinateY , miscellaneous)
1292
            // this method had its args flipped.
1293
            // code below allows backward compatibility with old arg order.
1294
            if (typeof lines === 'number') {
1295
                _first = y;
1296
                _second = lines;
1297
                _third = x;
1298
1299
                lines = _first;
1300
                x = _second;
1301
                y = _third;
1302
            }
1303
1304
            style = getStyle(style);
1305
            scale = scale === undef ? [1, 1] : scale;
0 ignored issues
show
Bug introduced by
The variable undef seems to be never initialized.
Loading history...
1306
1307
            // starting point
1308
            out(f3(x * k) + ' ' + f3((pageHeight - y) * k) + ' m ');
1309
1310
            scalex = scale[0];
1311
            scaley = scale[1];
1312
            l = lines.length;
1313
            //, x2, y2 // bezier only. In page default measurement "units", *after* scaling
1314
            //, x3, y3 // bezier only. In page default measurement "units", *after* scaling
1315
            // ending point for all, lines and bezier. . In page default measurement "units", *after* scaling
1316
            x4 = x; // last / ending point = starting point for first item.
1317
            y4 = y; // last / ending point = starting point for first item.
1318
1319
            for (i = 0; i < l; i++) {
1320
                leg = lines[i];
1321
                if (leg.length === 2) {
1322
                    // simple line
1323
                    x4 = leg[0] * scalex + x4; // here last x4 was prior ending point
1324
                    y4 = leg[1] * scaley + y4; // here last y4 was prior ending point
1325
                    out(f3(x4 * k) + ' ' + f3((pageHeight - y4) * k) + ' l');
1326
                } else {
1327
                    // bezier curve
1328
                    x2 = leg[0] * scalex + x4; // here last x4 is prior ending point
1329
                    y2 = leg[1] * scaley + y4; // here last y4 is prior ending point
1330
                    x3 = leg[2] * scalex + x4; // here last x4 is prior ending point
1331
                    y3 = leg[3] * scaley + y4; // here last y4 is prior ending point
1332
                    x4 = leg[4] * scalex + x4; // here last x4 was prior ending point
1333
                    y4 = leg[5] * scaley + y4; // here last y4 was prior ending point
1334
                    out(
1335
                        f3(x2 * k) + ' ' +
1336
                            f3((pageHeight - y2) * k) + ' ' +
1337
                            f3(x3 * k) + ' ' +
1338
                            f3((pageHeight - y3) * k) + ' ' +
1339
                            f3(x4 * k) + ' ' +
1340
                            f3((pageHeight - y4) * k) + ' c'
1341
                    );
1342
                }
1343
            }
1344
1345
            if (closed == true) {
1346
                out(' h');
1347
            }
1348
1349
            // stroking / filling / both the path
1350
            out(style);
1351
            return this;
1352
        };
1353
1354
        /**
1355
        Adds a rectangle to PDF
1356
1357
        @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1358
        @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1359
        @param {Number} w Width (in units declared at inception of PDF document)
1360
        @param {Number} h Height (in units declared at inception of PDF document)
1361
        @param {String} style (Defaults to active fill/stroke style) A string signalling if stroke, fill or both are to be applied.
1362
        @function
1363
        @returns {jsPDF}
1364
        @methodOf jsPDF#
1365
        @name rect
1366
         */
1367
        API.rect = function (x, y, w, h, style) {
1368
            var op = getStyle(style);
1369
            out([
1370
                f2(x * k),
1371
                f2((pageHeight - y) * k),
1372
                f2(w * k),
1373
                f2(-h * k),
1374
                're',
1375
                op
1376
            ].join(' '));
1377
            return this;
1378
        };
1379
1380
        /**
1381
        Adds a triangle to PDF
1382
1383
        @param {Number} x1 Coordinate (in units declared at inception of PDF document) against left edge of the page
1384
        @param {Number} y1 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1385
        @param {Number} x2 Coordinate (in units declared at inception of PDF document) against left edge of the page
1386
        @param {Number} y2 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1387
        @param {Number} x3 Coordinate (in units declared at inception of PDF document) against left edge of the page
1388
        @param {Number} y3 Coordinate (in units declared at inception of PDF document) against upper edge of the page
1389
        @param {String} style (Defaults to active fill/stroke style) A string signalling if stroke, fill or both are to be applied.
1390
        @function
1391
        @returns {jsPDF}
1392
        @methodOf jsPDF#
1393
        @name triangle
1394
         */
1395
        API.triangle = function (x1, y1, x2, y2, x3, y3, style) {
1396
            this.lines(
1397
                [
1398
                    [ x2 - x1, y2 - y1 ], // vector to point 2
1399
                    [ x3 - x2, y3 - y2 ], // vector to point 3
1400
                    [ x1 - x3, y1 - y3 ] // closing vector back to point 1
1401
                ],
1402
                x1,
1403
                y1, // start of path
1404
                [1, 1],
1405
                style,
1406
                true
1407
            );
1408
            return this;
1409
        };
1410
1411
        /**
1412
        Adds a rectangle with rounded corners to PDF
1413
1414
        @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1415
        @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1416
        @param {Number} w Width (in units declared at inception of PDF document)
1417
        @param {Number} h Height (in units declared at inception of PDF document)
1418
        @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
1419
        @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
0 ignored issues
show
Documentation introduced by
The parameter rx has already been documented on line 1418. The second definition is ignored.
Loading history...
1420
        @param {String} style (Defaults to active fill/stroke style) A string signalling if stroke, fill or both are to be applied.
1421
        @function
1422
        @returns {jsPDF}
1423
        @methodOf jsPDF#
1424
        @name roundedRect
1425
        */
1426
        API.roundedRect = function (x, y, w, h, rx, ry, style) {
1427
            var MyArc = 4 / 3 * (Math.SQRT2 - 1);
1428
            this.lines(
1429
                [
1430
                    [ (w - 2 * rx), 0 ],
1431
                    [ (rx * MyArc), 0, rx, ry - (ry * MyArc), rx, ry ],
1432
                    [ 0, (h - 2 * ry) ],
1433
                    [ 0, (ry * MyArc), -(rx * MyArc), ry, -rx, ry],
1434
                    [ (-w + 2 * rx), 0],
1435
                    [ -(rx * MyArc), 0, -rx, -(ry * MyArc), -rx, -ry],
1436
                    [ 0, (-h + 2 * ry)],
1437
                    [ 0, -(ry * MyArc), (rx * MyArc), -ry, rx, -ry]
1438
                ],
1439
                x + rx,
1440
                y, // start of path
1441
                [1, 1],
1442
                style
1443
            );
1444
            return this;
1445
        };
1446
1447
        /**
1448
        Adds an ellipse to PDF
1449
1450
        @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1451
        @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1452
        @param {Number} rx Radius along x axis (in units declared at inception of PDF document)
1453
        @param {Number} rx Radius along y axis (in units declared at inception of PDF document)
0 ignored issues
show
Documentation introduced by
The parameter rx has already been documented on line 1452. The second definition is ignored.
Loading history...
1454
        @param {String} style (Defaults to active fill/stroke style) A string signalling if stroke, fill or both are to be applied.
1455
        @function
1456
        @returns {jsPDF}
1457
        @methodOf jsPDF#
1458
        @name ellipse
1459
         */
1460
        API.ellipse = function (x, y, rx, ry, style) {
1461
            var op = getStyle(style),
1462
                lx = 4 / 3 * (Math.SQRT2 - 1) * rx,
1463
                ly = 4 / 3 * (Math.SQRT2 - 1) * ry;
1464
1465
            out([
1466
                f2((x + rx) * k),
1467
                f2((pageHeight - y) * k),
1468
                'm',
1469
                f2((x + rx) * k),
1470
                f2((pageHeight - (y - ly)) * k),
1471
                f2((x + lx) * k),
1472
                f2((pageHeight - (y - ry)) * k),
1473
                f2(x * k),
1474
                f2((pageHeight - (y - ry)) * k),
1475
                'c'
1476
            ].join(' '));
1477
            out([
1478
                f2((x - lx) * k),
1479
                f2((pageHeight - (y - ry)) * k),
1480
                f2((x - rx) * k),
1481
                f2((pageHeight - (y - ly)) * k),
1482
                f2((x - rx) * k),
1483
                f2((pageHeight - y) * k),
1484
                'c'
1485
            ].join(' '));
1486
            out([
1487
                f2((x - rx) * k),
1488
                f2((pageHeight - (y + ly)) * k),
1489
                f2((x - lx) * k),
1490
                f2((pageHeight - (y + ry)) * k),
1491
                f2(x * k),
1492
                f2((pageHeight - (y + ry)) * k),
1493
                'c'
1494
            ].join(' '));
1495
            out([
1496
                f2((x + lx) * k),
1497
                f2((pageHeight - (y + ry)) * k),
1498
                f2((x + rx) * k),
1499
                f2((pageHeight - (y + ly)) * k),
1500
                f2((x + rx) * k),
1501
                f2((pageHeight - y) * k),
1502
                'c',
1503
                op
1504
            ].join(' '));
1505
            return this;
1506
        };
1507
1508
        /**
1509
        Adds an circle to PDF
1510
1511
        @param {Number} x Coordinate (in units declared at inception of PDF document) against left edge of the page
1512
        @param {Number} y Coordinate (in units declared at inception of PDF document) against upper edge of the page
1513
        @param {Number} r Radius (in units declared at inception of PDF document)
1514
        @param {String} style (Defaults to active fill/stroke style) A string signalling if stroke, fill or both are to be applied.
1515
        @function
1516
        @returns {jsPDF}
1517
        @methodOf jsPDF#
1518
        @name circle
1519
         */
1520
        API.circle = function (x, y, r, style) {
1521
            return this.ellipse(x, y, r, r, style);
1522
        };
1523
1524
        /**
1525
        Adds a properties to the PDF document
1526
1527
        @param {Object} A property_name-to-property_value object structure.
0 ignored issues
show
Documentation introduced by
The parameter A does not exist. Did you maybe forget to remove this comment?
Loading history...
1528
        @function
1529
        @returns {jsPDF}
1530
        @methodOf jsPDF#
1531
        @name setProperties
1532
         */
1533
        API.setProperties = function (properties) {
1534
            // copying only those properties we can render.
1535
            var property;
1536
            for (property in documentProperties) {
1537
                if (documentProperties.hasOwnProperty(property) && properties[property]) {
1538
                    documentProperties[property] = properties[property];
1539
                }
1540
            }
1541
            return this;
1542
        };
1543
1544
        /**
1545
        Sets font size for upcoming text elements.
1546
1547
        @param {Number} size Font size in points.
1548
        @function
1549
        @returns {jsPDF}
1550
        @methodOf jsPDF#
1551
        @name setFontSize
1552
         */
1553
        API.setFontSize = function (size) {
1554
            activeFontSize = size;
1555
            return this;
1556
        };
1557
1558
        /**
1559
        Sets text font face, variant for upcoming text elements.
1560
        See output of jsPDF.getFontList() for possible font names, styles.
1561
1562
        @param {String} fontName Font name or family. Example: "times"
1563
        @param {String} fontStyle Font style or variant. Example: "italic"
1564
        @function
1565
        @returns {jsPDF}
1566
        @methodOf jsPDF#
1567
        @name setFont
1568
         */
1569
        API.setFont = function (fontName, fontStyle) {
1570
            activeFontKey = getFont(fontName, fontStyle);
1571
            // if font is not found, the above line blows up and we never go further
1572
            return this;
1573
        };
1574
1575
        /**
1576
        Switches font style or variant for upcoming text elements,
1577
        while keeping the font face or family same.
1578
        See output of jsPDF.getFontList() for possible font names, styles.
1579
1580
        @param {String} style Font style or variant. Example: "italic"
1581
        @function
1582
        @returns {jsPDF}
1583
        @methodOf jsPDF#
1584
        @name setFontStyle
1585
         */
1586
        API.setFontStyle = API.setFontType = function (style) {
1587
            var undef;
1588
            activeFontKey = getFont(undef, style);
0 ignored issues
show
Bug introduced by
The variable undef seems to be never initialized.
Loading history...
1589
            // if font is not found, the above line blows up and we never go further
1590
            return this;
1591
        };
1592
1593
        /**
1594
        Returns an object - a tree of fontName to fontStyle relationships available to
1595
        active PDF document.
1596
1597
        @public
1598
        @function
1599
        @returns {Object} Like {'times':['normal', 'italic', ... ], 'arial':['normal', 'bold', ... ], ... }
1600
        @methodOf jsPDF#
1601
        @name getFontList
1602
        */
1603
        API.getFontList = function () {
1604
            // TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added.
1605
            var list = {},
1606
                fontName,
1607
                fontStyle,
1608
                tmp;
1609
1610
            for (fontName in fontmap) {
1611
                if (fontmap.hasOwnProperty(fontName)) {
1612
                    list[fontName] = tmp = [];
1613
                    for (fontStyle in fontmap[fontName]) {
1614
                        if (fontmap[fontName].hasOwnProperty(fontStyle)) {
1615
                            tmp.push(fontStyle);
1616
                        }
1617
                    }
1618
                }
1619
            }
1620
1621
            return list;
1622
        };
1623
1624
        /**
1625
        Sets line width for upcoming lines.
1626
1627
        @param {Number} width Line width (in units declared at inception of PDF document)
1628
        @function
1629
        @returns {jsPDF}
1630
        @methodOf jsPDF#
1631
        @name setLineWidth
1632
         */
1633
        API.setLineWidth = function (width) {
1634
            out((width * k).toFixed(2) + ' w');
1635
            return this;
1636
        };
1637
1638
        /**
1639
        Sets the stroke color for upcoming elements.
1640
1641
        Depending on the number of arguments given, Gray, RGB, or CMYK
1642
        color space is implied.
1643
1644
        When only ch1 is given, "Gray" color space is implied and it
1645
        must be a value in the range from 0.00 (solid black) to to 1.00 (white)
1646
        if values are communicated as String types, or in range from 0 (black)
1647
        to 255 (white) if communicated as Number type.
1648
        The RGB-like 0-255 range is provided for backward compatibility.
1649
1650
        When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
1651
        value must be in the range from 0.00 (minimum intensity) to to 1.00
1652
        (max intensity) if values are communicated as String types, or
1653
        from 0 (min intensity) to to 255 (max intensity) if values are communicated
1654
        as Number types.
1655
        The RGB-like 0-255 range is provided for backward compatibility.
1656
1657
        When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
1658
        value must be a in the range from 0.00 (0% concentration) to to
1659
        1.00 (100% concentration)
1660
1661
        Because JavaScript treats fixed point numbers badly (rounds to
1662
        floating point nearest to binary representation) it is highly advised to
1663
        communicate the fractional numbers as String types, not JavaScript Number type.
1664
1665
        @param {Number|String} ch1 Color channel value
1666
        @param {Number|String} ch2 Color channel value
1667
        @param {Number|String} ch3 Color channel value
1668
        @param {Number|String} ch4 Color channel value
1669
1670
        @function
1671
        @returns {jsPDF}
1672
        @methodOf jsPDF#
1673
        @name setDrawColor
1674
         */
1675 View Code Duplication
        API.setDrawColor = function (ch1, ch2, ch3, ch4) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1676
            var color;
1677
            if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) {
1678
                // Gray color space.
1679
                if (typeof ch1 === 'string') {
1680
                    color = ch1 + ' G';
1681
                } else {
1682
                    color = f2(ch1 / 255) + ' G';
1683
                }
1684
            } else if (ch4 === undefined) {
1685
                // RGB
1686
                if (typeof ch1 === 'string') {
1687
                    color = [ch1, ch2, ch3, 'RG'].join(' ');
1688
                } else {
1689
                    color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'RG'].join(' ');
1690
                }
1691
            } else {
1692
                // CMYK
1693
                if (typeof ch1 === 'string') {
1694
                    color = [ch1, ch2, ch3, ch4, 'K'].join(' ');
1695
                } else {
1696
                    color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'K'].join(' ');
1697
                }
1698
            }
1699
1700
            out(color);
1701
            return this;
1702
        };
1703
1704
        /**
1705
        Sets the fill color for upcoming elements.
1706
1707
        Depending on the number of arguments given, Gray, RGB, or CMYK
1708
        color space is implied.
1709
1710
        When only ch1 is given, "Gray" color space is implied and it
1711
        must be a value in the range from 0.00 (solid black) to to 1.00 (white)
1712
        if values are communicated as String types, or in range from 0 (black)
1713
        to 255 (white) if communicated as Number type.
1714
        The RGB-like 0-255 range is provided for backward compatibility.
1715
1716
        When only ch1,ch2,ch3 are given, "RGB" color space is implied and each
1717
        value must be in the range from 0.00 (minimum intensity) to to 1.00
1718
        (max intensity) if values are communicated as String types, or
1719
        from 0 (min intensity) to to 255 (max intensity) if values are communicated
1720
        as Number types.
1721
        The RGB-like 0-255 range is provided for backward compatibility.
1722
1723
        When ch1,ch2,ch3,ch4 are given, "CMYK" color space is implied and each
1724
        value must be a in the range from 0.00 (0% concentration) to to
1725
        1.00 (100% concentration)
1726
1727
        Because JavaScript treats fixed point numbers badly (rounds to
1728
        floating point nearest to binary representation) it is highly advised to
1729
        communicate the fractional numbers as String types, not JavaScript Number type.
1730
1731
        @param {Number|String} ch1 Color channel value
1732
        @param {Number|String} ch2 Color channel value
1733
        @param {Number|String} ch3 Color channel value
1734
        @param {Number|String} ch4 Color channel value
1735
1736
        @function
1737
        @returns {jsPDF}
1738
        @methodOf jsPDF#
1739
        @name setFillColor
1740
         */
1741 View Code Duplication
        API.setFillColor = function (ch1, ch2, ch3, ch4) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1742
            var color;
1743
1744
            if (ch2 === undefined || (ch4 === undefined && ch1 === ch2 === ch3)) {
1745
                // Gray color space.
1746
                if (typeof ch1 === 'string') {
1747
                    color = ch1 + ' g';
1748
                } else {
1749
                    color = f2(ch1 / 255) + ' g';
1750
                }
1751
            } else if (ch4 === undefined) {
1752
                // RGB
1753
                if (typeof ch1 === 'string') {
1754
                    color = [ch1, ch2, ch3, 'rg'].join(' ');
1755
                } else {
1756
                    color = [f2(ch1 / 255), f2(ch2 / 255), f2(ch3 / 255), 'rg'].join(' ');
1757
                }
1758
            } else {
1759
                // CMYK
1760
                if (typeof ch1 === 'string') {
1761
                    color = [ch1, ch2, ch3, ch4, 'k'].join(' ');
1762
                } else {
1763
                    color = [f2(ch1), f2(ch2), f2(ch3), f2(ch4), 'k'].join(' ');
1764
                }
1765
            }
1766
1767
            out(color);
1768
            return this;
1769
        };
1770
1771
        /**
1772
        Sets the text color for upcoming elements.
1773
        If only one, first argument is given,
1774
        treats the value as gray-scale color value.
1775
1776
        @param {Number} r Red channel color value in range 0-255 or {String} r color value in hexadecimal, example: '#FFFFFF'
1777
        @param {Number} g Green channel color value in range 0-255
1778
        @param {Number} b Blue channel color value in range 0-255
1779
        @function
1780
        @returns {jsPDF}
1781
        @methodOf jsPDF#
1782
        @name setTextColor
1783
        */
1784
        API.setTextColor = function (r, g, b) {
1785
            var patt = /#[0-9A-Fa-f]{6}/;
1786
            if ((typeof r == 'string') && patt.test(r)) {
1787
                var hex = r.replace('#','');
1788
                var bigint = parseInt(hex, 16);
1789
                r = (bigint >> 16) & 255;
1790
                g = (bigint >> 8) & 255;
1791
                b = bigint & 255;
1792
            }
1793
1794
            if ((r === 0 && g === 0 && b === 0) || (typeof g === 'undefined')) {
1795
                textColor = f3(r / 255) + ' g';
1796
            } else {
1797
                textColor = [f3(r / 255), f3(g / 255), f3(b / 255), 'rg'].join(' ');
1798
            }
1799
            return this;
1800
        };
1801
1802
        /**
1803
        Is an Object providing a mapping from human-readable to
1804
        integer flag values designating the varieties of line cap
1805
        and join styles.
1806
1807
        @returns {Object}
1808
        @fieldOf jsPDF#
1809
        @name CapJoinStyles
1810
        */
1811
        API.CapJoinStyles = {
1812
            0: 0,
1813
            'butt': 0,
1814
            'but': 0,
1815
            'miter': 0,
1816
            1: 1,
1817
            'round': 1,
1818
            'rounded': 1,
1819
            'circle': 1,
1820
            2: 2,
1821
            'projecting': 2,
1822
            'project': 2,
1823
            'square': 2,
1824
            'bevel': 2
1825
        };
1826
1827
        /**
1828
        Sets the line cap styles
1829
        See {jsPDF.CapJoinStyles} for variants
1830
1831
        @param {String|Number} style A string or number identifying the type of line cap
1832
        @function
1833
        @returns {jsPDF}
1834
        @methodOf jsPDF#
1835
        @name setLineCap
1836
        */
1837
        API.setLineCap = function (style) {
1838
            var id = this.CapJoinStyles[style];
1839
            if (id === undefined) {
1840
                throw new Error("Line cap style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
1841
            }
1842
            lineCapID = id;
1843
            out(id.toString(10) + ' J');
1844
1845
            return this;
1846
        };
1847
1848
        /**
1849
        Sets the line join styles
1850
        See {jsPDF.CapJoinStyles} for variants
1851
1852
        @param {String|Number} style A string or number identifying the type of line join
1853
        @function
1854
        @returns {jsPDF}
1855
        @methodOf jsPDF#
1856
        @name setLineJoin
1857
        */
1858
        API.setLineJoin = function (style) {
1859
            var id = this.CapJoinStyles[style];
1860
            if (id === undefined) {
1861
                throw new Error("Line join style of '" + style + "' is not recognized. See or extend .CapJoinStyles property for valid styles");
1862
            }
1863
            lineJoinID = id;
1864
            out(id.toString(10) + ' j');
1865
1866
            return this;
1867
        };
1868
1869
        // Output is both an internal (for plugins) and external function
1870
        API.output = output;
1871
1872
        /**
1873
         * Saves as PDF document. An alias of jsPDF.output('save', 'filename.pdf')
1874
         * @param  {String} filename The filename including extension.
1875
         *
1876
         * @function
1877
         * @returns {jsPDF}
1878
         * @methodOf jsPDF#
1879
         * @name save
1880
         */
1881
        API.save = function (filename) {
1882
            API.output('save', filename);
1883
        };
1884
1885
        // applying plugins (more methods) ON TOP of built-in API.
1886
        // this is intentional as we allow plugins to override
1887
        // built-ins
1888
        for (plugin in jsPDF.API) {
1889
            if (jsPDF.API.hasOwnProperty(plugin)) {
1890
                if (plugin === 'events' && jsPDF.API.events.length) {
1891
                    (function (events, newEvents) {
1892
1893
                        // jsPDF.API.events is a JS Array of Arrays
1894
                        // where each Array is a pair of event name, handler
1895
                        // Events were added by plugins to the jsPDF instantiator.
1896
                        // These are always added to the new instance and some ran
1897
                        // during instantiation.
1898
1899
                        var eventname, handler_and_args, i;
1900
1901
                        for (i = newEvents.length - 1; i !== -1; i--) {
1902
                            // subscribe takes 3 args: 'topic', function, runonce_flag
1903
                            // if undefined, runonce is false.
1904
                            // users can attach callback directly,
1905
                            // or they can attach an array with [callback, runonce_flag]
1906
                            // that's what the "apply" magic is for below.
1907
                            eventname = newEvents[i][0];
1908
                            handler_and_args = newEvents[i][1];
1909
                            events.subscribe.apply(
1910
                                events,
1911
                                [eventname].concat(
1912
                                    typeof handler_and_args === 'function' ?
1913
                                            [ handler_and_args ] :
1914
                                            handler_and_args
1915
                                )
1916
                            );
1917
                        }
1918
                    }(events, jsPDF.API.events));
1919
                } else {
1920
                    API[plugin] = jsPDF.API[plugin];
1921
                }
1922
            }
1923
        }
1924
1925
        /////////////////////////////////////////
1926
        // continuing initilisation of jsPDF Document object
1927
        /////////////////////////////////////////
1928
1929
1930
        // Add the first page automatically
1931
        addFonts();
1932
        activeFontKey = 'F1';
1933
        _addPage();
1934
1935
        events.publish('initialized');
1936
1937
        return API;
1938
    }
1939
1940
/**
1941
jsPDF.API is a STATIC property of jsPDF class.
1942
jsPDF.API is an object you can add methods and properties to.
1943
The methods / properties you add will show up in new jsPDF objects.
1944
1945
One property is prepopulated. It is the 'events' Object. Plugin authors can add topics, callbacks to this object. These will be reassigned to all new instances of jsPDF.
1946
Examples:
1947
    jsPDF.API.events['initialized'] = function(){ 'this' is API object }
1948
    jsPDF.API.events['addFont'] = function(added_font_object){ 'this' is API object }
1949
1950
@static
1951
@public
1952
@memberOf jsPDF
1953
@name API
1954
1955
@example
1956
    jsPDF.API.mymethod = function(){
1957
        // 'this' will be ref to internal API object. see jsPDF source
1958
        // , so you can refer to built-in methods like so:
1959
        //     this.line(....)
1960
        //     this.text(....)
1961
    }
1962
    var pdfdoc = new jsPDF()
1963
    pdfdoc.mymethod() // <- !!!!!!
1964
*/
1965
    jsPDF.API = {'events': []};
1966
    jsPDF.version = "1.0.0-trunk";
1967
1968
    if (typeof define === 'function') {
1969
        define(function(){return jsPDF});
1970
    } else {
1971
        global.jsPDF = jsPDF;
1972
    }
1973
    return jsPDF;
1974
}(self));
1975
1976
/** @preserve 
1977
jsPDF split_text_to_size plugin
1978
Copyright (c) 2012 Willow Systems Corporation, willow-systems.com
1979
MIT license.
1980
*/
1981
/**
1982
 * Permission is hereby granted, free of charge, to any person obtaining
1983
 * a copy of this software and associated documentation files (the
1984
 * "Software"), to deal in the Software without restriction, including
1985
 * without limitation the rights to use, copy, modify, merge, publish,
1986
 * distribute, sublicense, and/or sell copies of the Software, and to
1987
 * permit persons to whom the Software is furnished to do so, subject to
1988
 * the following conditions:
1989
 * 
1990
 * The above copyright notice and this permission notice shall be
1991
 * included in all copies or substantial portions of the Software.
1992
 * 
1993
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1994
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1995
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1996
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
1997
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
1998
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1999
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2000
 * ====================================================================
2001
 */
2002
2003
;(function(API) {
2004
'use strict'
2005
2006
/**
2007
Returns an array of length matching length of the 'word' string, with each
2008
cell ocupied by the width of the char in that position.
2009
2010
@function
2011
@param word {String}
2012
@param widths {Object}
2013
@param kerning {Object}
2014
@returns {Array}
2015
*/
2016
var getCharWidthsArray = API.getCharWidthsArray = function(text, options){
2017
2018
	if (!options) {
2019
		options = {}
2020
	}
2021
2022
	var widths = options.widths ? options.widths : this.internal.getFont().metadata.Unicode.widths
2023
	, widthsFractionOf = widths.fof ? widths.fof : 1
2024
	, kerning = options.kerning ? options.kerning : this.internal.getFont().metadata.Unicode.kerning
2025
	, kerningFractionOf = kerning.fof ? kerning.fof : 1
2026
	
2027
	// console.log("widths, kergnings", widths, kerning)
2028
2029
	var i, l
2030
	, char_code
2031
	, char_width
0 ignored issues
show
Unused Code introduced by
The variable char_width seems to be never used. Consider removing it.
Loading history...
2032
	, prior_char_code = 0 // for kerning
2033
	, default_char_width = widths[0] || widthsFractionOf
2034
	, output = []
2035
2036
	for (i = 0, l = text.length; i < l; i++) {
2037
		char_code = text.charCodeAt(i)
2038
		output.push(
2039
			( widths[char_code] || default_char_width ) / widthsFractionOf + 
2040
			( kerning[char_code] && kerning[char_code][prior_char_code] || 0 ) / kerningFractionOf
2041
		)
2042
		prior_char_code = char_code
2043
	}
2044
2045
	return output
2046
}
2047
var getArraySum = function(array){
2048
	var i = array.length
2049
	, output = 0
2050
	while(i){
2051
		;i--;
2052
		output += array[i]
2053
	}
2054
	return output
2055
}
2056
/**
2057
Returns a widths of string in a given font, if the font size is set as 1 point.
2058
2059
In other words, this is "proportional" value. For 1 unit of font size, the length
2060
of the string will be that much.
2061
2062
Multiply by font size to get actual width in *points*
2063
Then divide by 72 to get inches or divide by (72/25.6) to get 'mm' etc.
2064
2065
@public
2066
@function
2067
@param
2068
@returns {Type}
2069
*/
2070
var getStringUnitWidth = API.getStringUnitWidth = function(text, options) {
0 ignored issues
show
Unused Code introduced by
The assignment to variable getStringUnitWidth seems to be never used. Consider removing it.
Loading history...
2071
	return getArraySum(getCharWidthsArray.call(this, text, options))
2072
}
2073
2074
/** 
2075
returns array of lines
2076
*/
2077
var splitLongWord = function(word, widths_array, firstLineMaxLen, maxLen){
2078
	var answer = []
2079
2080
	// 1st, chop off the piece that can fit on the hanging line.
2081
	var i = 0
2082
	, l = word.length
2083
	, workingLen = 0
2084
	while (i !== l && workingLen + widths_array[i] < firstLineMaxLen){
2085
		workingLen += widths_array[i]
2086
		;i++;
2087
	}
2088
	// this is first line.
2089
	answer.push(word.slice(0, i))
2090
2091
	// 2nd. Split the rest into maxLen pieces.
2092
	var startOfLine = i
2093
	workingLen = 0
2094
	while (i !== l){
2095
		if (workingLen + widths_array[i] > maxLen) {
2096
			answer.push(word.slice(startOfLine, i))
2097
			workingLen = 0
2098
			startOfLine = i
2099
		}
2100
		workingLen += widths_array[i]
2101
		;i++;
2102
	}
2103
	if (startOfLine !== i) {
2104
		answer.push(word.slice(startOfLine, i))
2105
	}
2106
2107
	return answer
2108
}
2109
2110
// Note, all sizing inputs for this function must be in "font measurement units"
2111
// By default, for PDF, it's "point".
2112
var splitParagraphIntoLines = function(text, maxlen, options){
2113
	// at this time works only on Western scripts, ones with space char
2114
	// separating the words. Feel free to expand.
2115
2116
	if (!options) {
2117
		options = {}
2118
	}
2119
2120
	var spaceCharWidth = getCharWidthsArray(' ', options)[0]
2121
2122
	var words = text.split(' ')
2123
2124
	var line = []
2125
	, lines = [line]
2126
	, line_length = options.textIndent || 0
2127
	, separator_length = 0
2128
	, current_word_length = 0
2129
	, word
2130
	, widths_array
2131
2132
	var i, l, tmp
2133
	for (i = 0, l = words.length; i < l; i++) {
2134
		word = words[i]
2135
		widths_array = getCharWidthsArray(word, options)
2136
		current_word_length = getArraySum(widths_array)
2137
2138
		if (line_length + separator_length + current_word_length > maxlen) {
2139
			if (current_word_length > maxlen) {
2140
				// this happens when you have space-less long URLs for example.
2141
				// we just chop these to size. We do NOT insert hiphens
2142
				tmp = splitLongWord(word, widths_array, maxlen - (line_length + separator_length), maxlen)
2143
				// first line we add to existing line object
2144
				line.push(tmp.shift()) // it's ok to have extra space indicator there
2145
				// last line we make into new line object
2146
				line = [tmp.pop()]
2147
				// lines in the middle we apped to lines object as whole lines
2148
				while(tmp.length){
2149
					lines.push([tmp.shift()]) // single fragment occupies whole line
2150
				}
2151
				current_word_length = getArraySum( widths_array.slice(word.length - line[0].length) )
2152
			} else {
2153
				// just put it on a new line
2154
				line = [word]
2155
			}
2156
2157
			// now we attach new line to lines
2158
			lines.push(line)
2159
2160
			line_length = current_word_length
2161
			separator_length = spaceCharWidth
2162
2163
		} else {
2164
			line.push(word)
2165
2166
			line_length += separator_length + current_word_length
2167
			separator_length = spaceCharWidth
2168
		}
2169
	}
2170
2171
	var output = []
2172
	for (i = 0, l = lines.length; i < l; i++) {
2173
		output.push( lines[i].join(' ') )
2174
	}
2175
	return output
2176
2177
}
2178
2179
/**
2180
Splits a given string into an array of strings. Uses 'size' value
2181
(in measurement units declared as default for the jsPDF instance)
2182
and the font's "widths" and "Kerning" tables, where availabe, to
2183
determine display length of a given string for a given font.
2184
2185
We use character's 100% of unit size (height) as width when Width
2186
table or other default width is not available.
2187
2188
@public
2189
@function
2190
@param text {String} Unencoded, regular JavaScript (Unicode, UTF-16 / UCS-2) string.
2191
@param size {Number} Nominal number, measured in units default to this instance of jsPDF.
2192
@param options {Object} Optional flags needed for chopper to do the right thing.
2193
@returns {Array} with strings chopped to size.
2194
*/
2195
API.splitTextToSize = function(text, maxlen, options) {
2196
	'use strict'
2197
2198
	if (!options) {
2199
		options = {}
2200
	}
2201
2202
	var fsize = options.fontSize || this.internal.getFontSize()
2203
	, newOptions = (function(options){
2204
		var widths = {0:1}
2205
		, kerning = {}
2206
2207
		if (!options.widths || !options.kerning) {
2208
			var f = this.internal.getFont(options.fontName, options.fontStyle)
2209
			, encoding = 'Unicode'
2210
			// NOT UTF8, NOT UTF16BE/LE, NOT UCS2BE/LE
2211
			// Actual JavaScript-native String's 16bit char codes used.
2212
			// no multi-byte logic here
2213
2214
			if (f.metadata[encoding]) {
2215
				return {
2216
					widths: f.metadata[encoding].widths || widths
2217
					, kerning: f.metadata[encoding].kerning || kerning
2218
				}
2219
			}
2220
		} else {
2221
			return 	{
2222
				widths: options.widths
2223
				, kerning: options.kerning
2224
			}			
2225
		}
2226
2227
		// then use default values
2228
		return 	{
2229
			widths: widths
2230
			, kerning: kerning
2231
		}
2232
	}).call(this, options)
2233
2234
	// first we split on end-of-line chars
2235
	var paragraphs 
2236
	if (text.match(/[\n\r]/)) {
2237
		paragraphs = text.split(/\r\n|\r|\n/g)
2238
	} else {
2239
		paragraphs = [text]
2240
	}
2241
2242
	// now we convert size (max length of line) into "font size units"
2243
	// at present time, the "font size unit" is always 'point'
2244
	// 'proportional' means, "in proportion to font size"
2245
	var fontUnit_maxLen = 1.0 * this.internal.scaleFactor * maxlen / fsize
2246
	// at this time, fsize is always in "points" regardless of the default measurement unit of the doc.
2247
	// this may change in the future?
2248
	// until then, proportional_maxlen is likely to be in 'points'
2249
2250
	// If first line is to be indented (shorter or longer) than maxLen 
2251
	// we indicate that by using CSS-style "text-indent" option.
2252
	// here it's in font units too (which is likely 'points')
2253
	// it can be negative (which makes the first line longer than maxLen)
2254
	newOptions.textIndent = options.textIndent ? 
2255
		options.textIndent * 1.0 * this.internal.scaleFactor / fsize : 
2256
		0
2257
2258
	var i, l
2259
	, output = []
2260
	for (i = 0, l = paragraphs.length; i < l; i++) {
2261
		output = output.concat(
2262
			splitParagraphIntoLines(
2263
				paragraphs[i]
2264
				, fontUnit_maxLen
2265
				, newOptions
2266
			)
2267
		)
2268
	}
2269
2270
	return output 
2271
}
2272
2273
})(jsPDF.API);
2274
2275
/** @preserve 
2276
 * jsPDF addImage plugin
2277
 * Copyright (c) 2012 Jason Siefken, https://github.com/siefkenj/
2278
 *               2013 Chris Dowling, https://github.com/gingerchris
2279
 *               2013 Trinh Ho, https://github.com/ineedfat
2280
 *               2013 Edwin Alejandro Perez, https://github.com/eaparango
2281
 *               2013 Norah Smith, https://github.com/burnburnrocket
2282
 *               2014 Diego Casorran, https://github.com/diegocr
2283
 *
2284
 * Permission is hereby granted, free of charge, to any person obtaining
2285
 * a copy of this software and associated documentation files (the
2286
 * "Software"), to deal in the Software without restriction, including
2287
 * without limitation the rights to use, copy, modify, merge, publish,
2288
 * distribute, sublicense, and/or sell copies of the Software, and to
2289
 * permit persons to whom the Software is furnished to do so, subject to
2290
 * the following conditions:
2291
 * 
2292
 * The above copyright notice and this permission notice shall be
2293
 * included in all copies or substantial portions of the Software.
2294
 * 
2295
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2296
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2297
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2298
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
2299
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2300
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2301
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2302
 */
2303
2304
;(function(jsPDFAPI) {
2305
	'use strict'
2306
	
2307
	var namespace = 'addImage_',
2308
		supported_image_types = ['jpeg', 'jpg', 'png'];
2309
	
2310
	
2311
	// Image functionality ported from pdf.js
2312
	var putImage = function(img) {
2313
		
2314
		var objectNumber = this.internal.newObject()
2315
		, out = this.internal.write
2316
		, putStream = this.internal.putStream
2317
	
2318
		img['n'] = objectNumber
2319
	
2320
		out('<</Type /XObject')
2321
		out('/Subtype /Image')
2322
		out('/Width ' + img['w'])
2323
		out('/Height ' + img['h'])
2324
		if (img['cs'] === this.color_spaces.INDEXED) {
2325
			out('/ColorSpace [/Indexed /DeviceRGB '
2326
					// if an indexed png defines more than one colour with transparency, we've created a smask  
2327
					+ (img['pal'].length / 3 - 1) + ' ' + ('smask' in img ? objectNumber + 2 : objectNumber + 1)
2328
					+ ' 0 R]');
2329
		} else {
2330
			out('/ColorSpace /' + img['cs']);
2331
			if (img['cs'] === this.color_spaces.DEVICE_CMYK) {
2332
				out('/Decode [1 0 1 0 1 0 1 0]');
2333
			}
2334
		}
2335
		out('/BitsPerComponent ' + img['bpc']);
2336
		if ('f' in img) {
2337
			out('/Filter /' + img['f']);
2338
		}
2339
		if ('dp' in img) {
2340
			out('/DecodeParms <<' + img['dp'] + '>>');
2341
		}
2342
		if ('trns' in img && img['trns'].constructor == Array) {
2343
			var trns = '',
2344
				i = 0,
2345
				len = img['trns'].length;
2346
			for (; i < len; i++)
2347
				trns += (img['trns'][i] + ' ' + img['trns'][i] + ' ');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2348
			out('/Mask [' + trns + ']');
2349
		}
2350
		if ('smask' in img) {
2351
			out('/SMask ' + (objectNumber + 1) + ' 0 R');
2352
		}
2353
		out('/Length ' + img['data'].length + '>>');
2354
	
2355
		putStream(img['data']);
2356
	
2357
		out('endobj');
2358
		
2359
		// Soft mask
2360
		if ('smask' in img) {
2361
			var dp = '/Predictor 15 /Colors 1 /BitsPerComponent ' + img['bpc'] + ' /Columns ' + img['w'];
2362
			var smask = {'w': img['w'], 'h': img['h'], 'cs': 'DeviceGray', 'bpc': img['bpc'], 'dp': dp, 'data': img['smask']};
2363
			if ('f' in img) 
2364
				smask.f = img['f'];
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2365
			putImage.call(this, smask);
2366
		}
2367
	    
2368
	    //Palette
2369
		if (img['cs'] === this.color_spaces.INDEXED) {
2370
			
2371
			this.internal.newObject();
2372
			//out('<< /Filter / ' + img['f'] +' /Length ' + img['pal'].length + '>>');
2373
			//putStream(zlib.compress(img['pal']));
2374
			out('<< /Length ' + img['pal'].length + '>>');
2375
			putStream(this.arrayBufferToBinaryString(new Uint8Array(img['pal'])));
2376
			out('endobj');
2377
		}
2378
	}
2379
	, putResourcesCallback = function() {
2380
		var images = this.internal.collections[namespace + 'images']
2381
		for ( var i in images ) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
2382
			putImage.call(this, images[i])
2383
		}
2384
	}
2385
	, putXObjectsDictCallback = function(){
2386
		var images = this.internal.collections[namespace + 'images']
2387
		, out = this.internal.write
2388
		, image
2389
		for (var i in images) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
2390
			image = images[i]
2391
			out(
2392
				'/I' + image['i']
2393
				, image['n']
2394
				, '0'
2395
				, 'R'
2396
			)
2397
		}
2398
	}
2399
	, checkCompressValue = function(value) {
2400
		if(value && typeof value === 'string')
2401
			value = value.toUpperCase();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2402
		return value in jsPDFAPI.image_compression ? value : jsPDFAPI.image_compression.NONE;
2403
	}
2404
	, getImages = function() {
2405
		var images = this.internal.collections[namespace + 'images'];
2406
		//first run, so initialise stuff
2407
		if(!images) {
2408
			this.internal.collections[namespace + 'images'] = images = {};
2409
			this.internal.events.subscribe('putResources', putResourcesCallback);
2410
			this.internal.events.subscribe('putXobjectDict', putXObjectsDictCallback);
2411
		}
2412
		
2413
		return images;
2414
	}
2415
	, getImageIndex = function(images) {
2416
		var imageIndex = 0;
2417
		
2418
		if (images){
2419
			// this is NOT the first time this method is ran on this instance of jsPDF object.
2420
			imageIndex = Object.keys ? 
2421
			Object.keys(images).length :
2422
			(function(o){
2423
				var i = 0
2424
				for (var e in o){if(o.hasOwnProperty(e)){ i++ }}
2425
				return i
2426
			})(images)
2427
		}
2428
		
2429
		return imageIndex;
2430
	}
2431
	, notDefined = function(value) {
2432
		return typeof value === 'undefined' || value === null;
2433
	}
2434
	, generateAliasFromData = function(data) {
0 ignored issues
show
Unused Code introduced by
The parameter data is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
2435
		// TODO: Alias dynamic generation from imageData's checksum/hash
2436
		return undefined;
2437
	}
2438
	, doesNotSupportImageType = function(type) {
2439
		return supported_image_types.indexOf(type) === -1;
2440
	}
2441
	, processMethodNotEnabled = function(type) {
2442
		return typeof jsPDFAPI['process' + type.toUpperCase()] !== 'function';
2443
	}
2444
	, isDOMElement = function(object) {
2445
		return typeof object === 'object' && object.nodeType === 1;
2446
	}
2447
	, createDataURIFromElement = function(imageData, format) {
2448
		
2449
		var canvas = document.createElement('canvas');
2450
	    canvas.width = imageData.clientWidth || imageData.width;
2451
	    canvas.height = imageData.clientHeight || imageData.height;
2452
	
2453
	    var ctx = canvas.getContext('2d');
2454
	    if (!ctx) {
2455
	        throw ('addImage requires canvas to be supported by browser.');
2456
	    }
2457
	    ctx.drawImage(imageData, 0, 0, canvas.width, canvas.height);
2458
	    
2459
	    return canvas.toDataURL(format == 'png' ? 'image/png' : 'image/jpeg');
2460
	}
2461
	,checkImagesForAlias = function(imageData, images) {
2462
		var cached_info;
2463
		if(images) {
2464
			for(var e in images) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
2465
				if(imageData === images[e].alias) {
2466
					cached_info = images[e];
2467
					break;
2468
				}
2469
			}
2470
		}
2471
		return cached_info;
0 ignored issues
show
Bug introduced by
The variable cached_info seems to not be initialized for all possible execution paths.
Loading history...
2472
	}
2473
	,determineWidthAndHeight = function(w, h) {
2474
		if (!w && !h) {
2475
			w = -96;
2476
			h = -96;
2477
		}
2478
		if (w < 0) {
2479
			w = (-1) * info['w'] * 72 / w / this.internal.scaleFactor;
0 ignored issues
show
Bug introduced by
The variable info seems to be never declared. If this is a global, consider adding a /** global: info */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
2480
		}
2481
		if (h < 0) {
2482
			h = (-1) * info['h'] * 72 / h / this.internal.scaleFactor;
2483
		}
2484
		if (w === 0) {
2485
			w = h * info['w'] / info['h'];
2486
		}
2487
		if (h === 0) {
2488
			h = w * info['h'] / info['w'];
2489
		}
2490
		
2491
		return [w, h];
2492
	}
2493
	, writeImageToPDF = function(x, y, w, h, info, index, images) {
2494
		var dims = determineWidthAndHeight(w, h),
2495
			coord = this.internal.getCoordinateString,
2496
			vcoord = this.internal.getVerticalCoordinateString;
2497
		
2498
		w = dims[0];
2499
		h = dims[1];
2500
		
2501
		images[index] = info;
2502
		
2503
		this.internal.write(
2504
			'q'
2505
			, coord(w)
2506
			, '0 0'
2507
			, coord(h) // TODO: check if this should be shifted by vcoord
2508
			, coord(x)
2509
			, vcoord(y + h)
2510
			, 'cm /I'+info['i']
2511
			, 'Do Q'
2512
		)
2513
	};
2514
	
2515
	
2516
	/**
2517
	 * COLOR SPACES
2518
	 */
2519
	jsPDFAPI.color_spaces = {
2520
		DEVICE_RGB:'DeviceRGB',
2521
		DEVICE_GRAY:'DeviceGray',
2522
		DEVICE_CMYK:'DeviceCMYK',
2523
		CAL_GREY:'CalGray',
2524
		CAL_RGB:'CalRGB',
2525
		LAB:'Lab',
2526
		ICC_BASED:'ICCBased',
2527
		INDEXED:'Indexed',
2528
		PATTERN:'Pattern',
2529
		SEPERATION:'Seperation',
2530
		DEVICE_N:'DeviceN'
2531
	};
2532
	
2533
	/**
2534
	 * DECODE METHODS
2535
	 */
2536
	jsPDFAPI.decode = {
2537
		DCT_DECODE:'DCTDecode',
2538
		FLATE_DECODE:'FlateDecode',
2539
		LZW_DECODE:'LZWDecode',
2540
		JPX_DECODE:'JPXDecode',
2541
		JBIG2_DECODE:'JBIG2Decode',
2542
		ASCII85_DECODE:'ASCII85Decode',
2543
		ASCII_HEX_DECODE:'ASCIIHexDecode',
2544
		RUN_LENGTH_DECODE:'RunLengthDecode',
2545
		CCITT_FAX_DECODE:'CCITTFaxDecode'
2546
	};
2547
	
2548
	/**
2549
	 * IMAGE COMPRESSION TYPES
2550
	 */
2551
	jsPDFAPI.image_compression = {
2552
		NONE: 'NONE',
2553
		FAST: 'FAST',
2554
		MEDIUM: 'MEDIUM',
2555
		SLOW: 'SLOW'
2556
	};
2557
	
2558
	
2559
	jsPDFAPI.isString = function(object) {
2560
		return typeof object === 'string';
2561
	};
2562
	
2563
	/**
2564
	 * Strips out and returns info from a valid base64 data URI
2565
	 * @param {String[dataURI]} a valid data URI of format 'data:[<MIME-type>][;base64],<data>'
0 ignored issues
show
Documentation introduced by
The parameter a does not exist. Did you maybe forget to remove this comment?
Loading history...
2566
	 * @returns an Array containing the following
2567
	 * [0] the complete data URI
2568
	 * [1] <MIME-type>
2569
	 * [2] format - the second part of the mime-type i.e 'png' in 'image/png'
2570
	 * [4] <data>
2571
	 */
2572
	jsPDFAPI.extractInfoFromBase64DataURI = function(dataURI) {
2573
		return /^data:([\w]+?\/([\w]+?));base64,(.+?)$/g.exec(dataURI);
2574
	};
2575
	
2576
	/**
2577
	 * Check to see if ArrayBuffer is supported
2578
	 */
2579
	jsPDFAPI.supportsArrayBuffer = function() {
2580
		return typeof ArrayBuffer === 'function';
2581
	};
2582
	
2583
	/**
2584
	 * Tests supplied object to determine if ArrayBuffer
2585
	 * @param {Object[object]} 
2586
	 */
2587
	jsPDFAPI.isArrayBuffer = function(object) {
2588
		if(!this.supportsArrayBuffer())
2589
	        return false;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2590
		return object instanceof ArrayBuffer;
2591
	};
2592
	
2593
	/**
2594
	 * Tests supplied object to determine if it implements the ArrayBufferView (TypedArray) interface
2595
	 * @param {Object[object]} 
2596
	 */
2597
	jsPDFAPI.isArrayBufferView = function(object) {
2598
		if(!this.supportsArrayBuffer())
2599
	        return false;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2600
		return (object instanceof Int8Array ||
2601
				object instanceof Uint8Array ||
2602
				object instanceof Uint8ClampedArray ||
2603
				object instanceof Int16Array ||
2604
				object instanceof Uint16Array ||
2605
				object instanceof Int32Array ||
2606
				object instanceof Uint32Array ||
2607
				object instanceof Float32Array ||
2608
				object instanceof Float64Array );
2609
	};
2610
	
2611
	/**
2612
	 * Exactly what it says on the tin
2613
	 */
2614
	jsPDFAPI.binaryStringToUint8Array = function(binary_string) {
2615
		/*
2616
		 * not sure how efficient this will be will bigger files. Is there a native method?
2617
		 */
2618
		var len = binary_string.length;
2619
	    var bytes = new Uint8Array( len );
2620
	    for (var i = 0; i < len; i++) {
2621
	        bytes[i] = binary_string.charCodeAt(i);
2622
	    }
2623
	    return bytes;
2624
	};
2625
	
2626
	/**
2627
	 * @see this discussion
2628
	 * http://stackoverflow.com/questions/6965107/converting-between-strings-and-arraybuffers
2629
	 * 
2630
	 * As stated, i imagine the method below is highly inefficent for large files.
2631
	 * 
2632
	 * Also of note from Mozilla,
2633
	 * 
2634
	 * "However, this is slow and error-prone, due to the need for multiple conversions (especially if the binary data is not actually byte-format data, but, for example, 32-bit integers or floats)."
2635
	 * 
2636
	 * https://developer.mozilla.org/en-US/Add-ons/Code_snippets/StringView
2637
	 * 
2638
	 * Although i'm strugglig to see how StringView solves this issue? Doesn't appear to be a direct method for conversion?
2639
	 * 
2640
	 * Async method using Blob and FileReader could be best, but i'm not sure how to fit it into the flow?
2641
	 */
2642
	jsPDFAPI.arrayBufferToBinaryString = function(buffer) {
2643
		if(this.isArrayBuffer(buffer))
2644
			buffer = new Uint8Array(buffer);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2645
		
2646
	    var binary_string = '';
2647
	    var len = buffer.byteLength;
2648
	    for (var i = 0; i < len; i++) {
2649
	        binary_string += String.fromCharCode(buffer[i]);
2650
	    }
2651
	    return binary_string;
2652
	    /*
2653
	     * Another solution is the method below - convert array buffer straight to base64 and then use atob
2654
	     */
2655
		//return atob(this.arrayBufferToBase64(buffer));
2656
	};
2657
	
2658
	/**
2659
	 * Converts an ArrayBuffer directly to base64
2660
	 * 
2661
	 * Taken from here
2662
	 * 
2663
	 * http://jsperf.com/encoding-xhr-image-data/31
2664
	 * 
2665
	 * Need to test if this is a better solution for larger files
2666
	 * 
2667
	 */
2668
	jsPDFAPI.arrayBufferToBase64 = function(arrayBuffer) {
2669
		var base64    = ''
2670
		var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
2671
2672
		var bytes         = new Uint8Array(arrayBuffer)
2673
		var byteLength    = bytes.byteLength
2674
		var byteRemainder = byteLength % 3
2675
		var mainLength    = byteLength - byteRemainder
2676
2677
		var a, b, c, d
2678
		var chunk
2679
2680
		// Main loop deals with bytes in chunks of 3
2681
		for (var i = 0; i < mainLength; i = i + 3) {
2682
			// Combine the three bytes into a single integer
2683
			chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
2684
2685
			// Use bitmasks to extract 6-bit segments from the triplet
2686
			a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
2687
			b = (chunk & 258048)   >> 12 // 258048   = (2^6 - 1) << 12
2688
			c = (chunk & 4032)     >>  6 // 4032     = (2^6 - 1) << 6
2689
			d = chunk & 63               // 63       = 2^6 - 1
2690
2691
			// Convert the raw binary segments to the appropriate ASCII encoding
2692
			base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]
2693
		}
2694
2695
		// Deal with the remaining bytes and padding
2696
		if (byteRemainder == 1) {
2697
			chunk = bytes[mainLength]
2698
2699
			a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
2700
2701
			// Set the 4 least significant bits to zero
2702
			b = (chunk & 3)   << 4 // 3   = 2^2 - 1
2703
2704
			base64 += encodings[a] + encodings[b] + '=='
2705
		} else if (byteRemainder == 2) {
2706
			chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]
2707
2708
			a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
2709
			b = (chunk & 1008)  >>  4 // 1008  = (2^6 - 1) << 4
2710
2711
			// Set the 2 least significant bits to zero
2712
			c = (chunk & 15)    <<  2 // 15    = 2^4 - 1
2713
2714
			base64 += encodings[a] + encodings[b] + encodings[c] + '='
2715
		}
2716
2717
		return base64
2718
	};
2719
	
2720
	
2721
	jsPDFAPI.createImageInfo = function(data, wd, ht, cs, bpc, f, imageIndex, alias, dp, trns, pal, smask) {
2722
		var info = {
2723
				alias:alias,
2724
				w : wd,
2725
				h : ht,
2726
				cs : cs,
2727
				bpc : bpc,
2728
				i : imageIndex,
2729
				data : data
2730
				// n: objectNumber will be added by putImage code
2731
			};
2732
		
2733
		if(f) info.f = f;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2734
		if(dp) info.dp = dp;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2735
		if(trns) info.trns = trns;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2736
		if(pal) info.pal = pal;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2737
		if(smask) info.smask = smask;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2738
		
2739
		return info;
2740
	};
2741
	
2742
	jsPDFAPI.addImage = function(imageData, format, x, y, w, h, alias, compression) {
2743
		'use strict'
2744
		
2745
		if(typeof format === 'number') {
2746
			var tmp = h;
2747
			h = w;
2748
			w = y;
2749
			y = x;
2750
			x = format;
2751
			format = tmp || 'jpeg';
2752
		}
2753
		
2754
		var images = getImages.call(this),//initalises internals and events on first run
2755
			cached_info,
2756
			dataAsBinaryString;
2757
		
2758
		compression = checkCompressValue(compression);
2759
		format = format.toLowerCase();
2760
		
2761
		if(notDefined(alias))
2762
			alias = generateAliasFromData(imageData);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2763
		
2764
		if(isDOMElement(imageData))
2765
			imageData = createDataURIFromElement(imageData, format);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2766
				
2767
		if(this.isString(imageData)) {
2768
			
2769
			var base64Info = this.extractInfoFromBase64DataURI(imageData);
2770
			
2771
			if(base64Info) {
2772
				
2773
				format = base64Info[2];
2774
				imageData = atob(base64Info[3]);//convert to binary string
2775
				
2776
				/*
2777
				 * need to test if it's more efficent to convert all binary strings
2778
				 * to TypedArray - or should we just leave and process as string?
2779
				 */
2780
				if(this.supportsArrayBuffer()) {
2781
					dataAsBinaryString = imageData;
2782
					imageData = this.binaryStringToUint8Array(imageData);
2783
				}
2784
				
2785
			}else{
2786
				// This is neither raw jpeg-data nor a data uri; alias?
2787
				if(imageData.charCodeAt(0) !== 0xff)
2788
					cached_info = checkImagesForAlias(imageData, images);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2789
			}
2790
		}
2791
		
2792
		if(doesNotSupportImageType(format))
2793
			throw new Error('addImage currently only supports formats ' + supported_image_types + ', not \''+format+'\'');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2794
		
2795
		if(processMethodNotEnabled(format))
2796
			throw new Error('please ensure that the plugin for \''+format+'\' support is added');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2797
		
2798
		var imageIndex = getImageIndex(images),
2799
			info = cached_info;
0 ignored issues
show
Bug introduced by
The variable cached_info seems to not be initialized for all possible execution paths.
Loading history...
2800
2801
		if(!info)			
2802
			info = this['process' + format.toUpperCase()](imageData, imageIndex, alias, compression, dataAsBinaryString);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
Bug introduced by
The variable dataAsBinaryString seems to not be initialized for all possible execution paths.
Loading history...
2803
		
2804
		if(!info)
2805
			throw new Error('An unkwown error occurred whilst processing the image');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2806
		
2807
		writeImageToPDF.call(this, x, y, w, h, info, imageIndex, images);
2808
	
2809
		return this 
2810
	};
2811
	
2812
	
2813
	/**
2814
	 * JPEG SUPPORT
2815
	 **/
2816
	
2817
	//takes a string imgData containing the raw bytes of
2818
	//a jpeg image and returns [width, height]
2819
	//Algorithm from: http://www.64lines.com/jpeg-width-height
2820 View Code Duplication
	var getJpegSize = function(imgData) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
2821
		'use strict'
2822
		var width, height;
2823
		// Verify we have a valid jpeg header 0xff,0xd8,0xff,0xe0,?,?,'J','F','I','F',0x00
2824
		if (!imgData.charCodeAt(0) === 0xff ||
2825
			!imgData.charCodeAt(1) === 0xd8 ||
2826
			!imgData.charCodeAt(2) === 0xff ||
2827
			!imgData.charCodeAt(3) === 0xe0 ||
2828
			!imgData.charCodeAt(6) === 'J'.charCodeAt(0) ||
2829
			!imgData.charCodeAt(7) === 'F'.charCodeAt(0) ||
2830
			!imgData.charCodeAt(8) === 'I'.charCodeAt(0) ||
2831
			!imgData.charCodeAt(9) === 'F'.charCodeAt(0) ||
2832
			!imgData.charCodeAt(10) === 0x00) {
2833
				throw new Error('getJpegSize requires a binary string jpeg file')
2834
		}
2835
		var blockLength = imgData.charCodeAt(4)*256 + imgData.charCodeAt(5);
2836
		var i = 4, len = imgData.length;
2837
		while ( i < len ) {
2838
			i += blockLength;
2839
			if (imgData.charCodeAt(i) !== 0xff) {
2840
				throw new Error('getJpegSize could not find the size of the image');
2841
			}
2842
			if (imgData.charCodeAt(i+1) === 0xc0 || //(SOF) Huffman  - Baseline DCT
2843
			    imgData.charCodeAt(i+1) === 0xc1 || //(SOF) Huffman  - Extended sequential DCT 
2844
			    imgData.charCodeAt(i+1) === 0xc2 || // Progressive DCT (SOF2)
2845
			    imgData.charCodeAt(i+1) === 0xc3 || // Spatial (sequential) lossless (SOF3)
2846
			    imgData.charCodeAt(i+1) === 0xc4 || // Differential sequential DCT (SOF5)
2847
			    imgData.charCodeAt(i+1) === 0xc5 || // Differential progressive DCT (SOF6)
2848
			    imgData.charCodeAt(i+1) === 0xc6 || // Differential spatial (SOF7)
2849
			    imgData.charCodeAt(i+1) === 0xc7) {
2850
				height = imgData.charCodeAt(i+5)*256 + imgData.charCodeAt(i+6);
2851
				width = imgData.charCodeAt(i+7)*256 + imgData.charCodeAt(i+8);
2852
				return [width, height];
2853
			} else {
2854
				i += 2;
2855
				blockLength = imgData.charCodeAt(i)*256 + imgData.charCodeAt(i+1)
2856
			}
2857
		}
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
2858
	}
2859
	, getJpegSizeFromBytes = function(data) {
2860
		
2861
		var hdr = (data[0] << 8) | data[1];
2862
		
2863
		if(hdr !== 0xFFD8)
2864
			throw new Error('Supplied data is not a JPEG');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2865
		
2866
		var len = data.length,
2867
			block = (data[4] << 8) + data[5],
2868
			pos = 4,
2869
			bytes, width, height;
2870
		
2871
		while(pos < len) {
2872
			pos += block;
2873
			bytes = readBytes(data, pos);
2874
			block = (bytes[2] << 8) + bytes[3];
2875
			if((bytes[1] === 0xC0 || bytes[1] === 0xC2) && bytes[0] === 0xFF && block > 7) {
2876
				bytes = readBytes(data, pos + 5);
2877
				width = (bytes[2] << 8) + bytes[3];
2878
				height = (bytes[0] << 8) + bytes[1];
2879
				return {width:width, height:height};
2880
			}
2881
			
2882
			pos+=2;
2883
		}
2884
		
2885
		throw new Error('getJpegSizeFromBytes could not find the size of the image');
2886
	}
2887
	, readBytes = function(data, offset) {
2888
		return data.subarray(offset, offset+ 4);
2889
	};
2890
	
2891
	
2892
	jsPDFAPI.processJPEG = function(data, index, alias, compression, dataAsBinaryString) {
2893
		'use strict'
2894
		var colorSpace = this.color_spaces.DEVICE_RGB,
2895
			filter = this.decode.DCT_DECODE,
2896
			bpc = 8,
2897
			dims;
2898
		
2899
		if(this.isString(data)) {
2900
			dims = getJpegSize(data);
2901
			return this.createImageInfo(data, dims[0], dims[1], colorSpace, bpc, filter, index, alias);
2902
		}
2903
		
2904
		if(this.isArrayBuffer(data))
2905
			data = new Uint8Array(data);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
2906
		
2907
		if(this.isArrayBufferView(data)) {
2908
			
2909
			dims = getJpegSizeFromBytes(data);
2910
			
2911
			// if we already have a stored binary string rep use that
2912
			data = dataAsBinaryString || this.arrayBufferToBinaryString(data);
2913
			
2914
			return this.createImageInfo(data, dims.width, dims.height, colorSpace, bpc, filter, index, alias);
2915
		}
2916
		
2917
		return null;
2918
	};
2919
	
2920
	jsPDFAPI.processJPG = function(data, index, alias, compression, dataAsBinaryString) {
2921
		return this.processJPEG(data, index, alias, compression, dataAsBinaryString);
2922
	}
2923
2924
})(jsPDF.API);
2925
2926
/* FileSaver.js
2927
 * A saveAs() FileSaver implementation.
2928
 * 2013-01-23
2929
 * 
2930
 * By Eli Grey, http://eligrey.com
2931
 * License: X11/MIT
2932
 *   See LICENSE.md
2933
 */
2934
2935
/*global self */
2936
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
2937
  plusplus: true */
2938
2939
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
2940
2941
var saveAs = saveAs
0 ignored issues
show
Bug introduced by
The variable saveAs seems to be never initialized.
Loading history...
2942
  || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator))
0 ignored issues
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
2943
  || (function(view) {
2944
	"use strict";
2945
	var
2946
		  doc = view.document
2947
		  // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet
2948
		, get_URL = function() {
2949
			return view.URL || view.webkitURL || view;
2950
		}
2951
		, URL = view.URL || view.webkitURL || view
2952
		, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
2953
		, can_use_save_link = "download" in save_link
2954
		, click = function(node) {
2955
			var event = doc.createEvent("MouseEvents");
2956
			event.initMouseEvent(
2957
				"click", true, false, view, 0, 0, 0, 0, 0
2958
				, false, false, false, false, 0, null
2959
			);
2960
			return node.dispatchEvent(event); // false if event was cancelled
2961
		}
2962
		, webkit_req_fs = view.webkitRequestFileSystem
2963
		, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
2964
		, throw_outside = function (ex) {
2965
			(view.setImmediate || view.setTimeout)(function() {
2966
				throw ex;
2967
			}, 0);
2968
		}
2969
		, force_saveable_type = "application/octet-stream"
2970
		, fs_min_size = 0
2971
		, deletion_queue = []
2972
		, process_deletion_queue = function() {
2973
			var i = deletion_queue.length;
2974
			while (i--) {
2975
				var file = deletion_queue[i];
2976
				if (typeof file === "string") { // file is an object URL
2977
					URL.revokeObjectURL(file);
2978
				} else { // file is a File
2979
					file.remove();
2980
				}
2981
			}
2982
			deletion_queue.length = 0; // clear queue
2983
		}
2984
		, dispatch = function(filesaver, event_types, event) {
2985
			event_types = [].concat(event_types);
2986
			var i = event_types.length;
2987
			while (i--) {
2988
				var listener = filesaver["on" + event_types[i]];
2989
				if (typeof listener === "function") {
2990
					try {
2991
						listener.call(filesaver, event || filesaver);
2992
					} catch (ex) {
2993
						throw_outside(ex);
2994
					}
2995
				}
2996
			}
2997
		}
2998
		, FileSaver = function(blob, name) {
2999
			// First try a.download, then web filesystem, then object URLs
3000
			var
3001
				  filesaver = this
3002
				, type = blob.type
3003
				, blob_changed = false
3004
				, object_url
3005
				, target_view
3006
				, get_object_url = function() {
3007
					var object_url = get_URL().createObjectURL(blob);
3008
					deletion_queue.push(object_url);
3009
					return object_url;
3010
				}
3011
				, dispatch_all = function() {
3012
					dispatch(filesaver, "writestart progress write writeend".split(" "));
3013
				}
3014
				// on any filesys errors revert to saving with object URLs
3015
				, fs_error = function() {
3016
					// don't create more object URLs than needed
3017
					if (blob_changed || !object_url) {
3018
						object_url = get_object_url(blob);
0 ignored issues
show
Bug introduced by
The call to get_object_url seems to have too many arguments starting with blob.
Loading history...
3019
					}
3020
					if (target_view) {
3021
						target_view.location.href = object_url;
3022
					}
3023
					filesaver.readyState = filesaver.DONE;
3024
					dispatch_all();
3025
				}
3026
				, abortable = function(func) {
3027
					return function() {
3028
						if (filesaver.readyState !== filesaver.DONE) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if filesaver.readyState !== filesaver.DONE is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
3029
							return func.apply(this, arguments);
3030
						}
3031
					};
3032
				}
3033
				, create_if_not_found = {create: true, exclusive: false}
3034
				, slice
3035
			;
3036
			filesaver.readyState = filesaver.INIT;
3037
			if (!name) {
3038
				name = "download";
3039
			}
3040
			if (can_use_save_link) {
3041
				object_url = get_object_url(blob);
0 ignored issues
show
Bug introduced by
The call to get_object_url seems to have too many arguments starting with blob.
Loading history...
3042
				save_link.href = object_url;
3043
				save_link.download = name;
3044
				if (click(save_link)) {
3045
					filesaver.readyState = filesaver.DONE;
3046
					dispatch_all();
3047
					return;
3048
				}
3049
			}
3050
			// Object and web filesystem URLs have a problem saving in Google Chrome when
3051
			// viewed in a tab, so I force save with application/octet-stream
3052
			// http://code.google.com/p/chromium/issues/detail?id=91158
3053
			if (view.chrome && type && type !== force_saveable_type) {
3054
				slice = blob.slice || blob.webkitSlice;
3055
				blob = slice.call(blob, 0, blob.size, force_saveable_type);
3056
				blob_changed = true;
3057
			}
3058
			// Since I can't be sure that the guessed media type will trigger a download
3059
			// in WebKit, I append .download to the filename.
3060
			// https://bugs.webkit.org/show_bug.cgi?id=65440
3061
			if (webkit_req_fs && name !== "download") {
3062
				name += ".download";
3063
			}
3064
			if (type === force_saveable_type || webkit_req_fs) {
3065
				target_view = view;
3066
			} else {
3067
				target_view = view.open();
3068
			}
3069
			if (!req_fs) {
3070
				fs_error();
3071
				return;
3072
			}
3073
			fs_min_size += blob.size;
3074
			req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
3075
				fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
3076
					var save = function() {
3077
						dir.getFile(name, create_if_not_found, abortable(function(file) {
3078
							file.createWriter(abortable(function(writer) {
3079
								writer.onwriteend = function(event) {
3080
									target_view.location.href = file.toURL();
3081
									deletion_queue.push(file);
3082
									filesaver.readyState = filesaver.DONE;
3083
									dispatch(filesaver, "writeend", event);
3084
								};
3085
								writer.onerror = function() {
3086
									var error = writer.error;
3087
									if (error.code !== error.ABORT_ERR) {
3088
										fs_error();
3089
									}
3090
								};
3091
								"writestart progress write abort".split(" ").forEach(function(event) {
3092
									writer["on" + event] = filesaver["on" + event];
3093
								});
3094
								writer.write(blob);
3095
								filesaver.abort = function() {
3096
									writer.abort();
3097
									filesaver.readyState = filesaver.DONE;
3098
								};
3099
								filesaver.readyState = filesaver.WRITING;
3100
							}), fs_error);
3101
						}), fs_error);
3102
					};
3103
					dir.getFile(name, {create: false}, abortable(function(file) {
3104
						// delete file if it already exists
3105
						file.remove();
3106
						save();
3107
					}), abortable(function(ex) {
3108
						if (ex.code === ex.NOT_FOUND_ERR) {
3109
							save();
3110
						} else {
3111
							fs_error();
3112
						}
3113
					}));
3114
				}), fs_error);
3115
			}), fs_error);
3116
		}
3117
		, FS_proto = FileSaver.prototype
3118
		, saveAs = function(blob, name) {
3119
			return new FileSaver(blob, name);
3120
		}
3121
	;
3122
	FS_proto.abort = function() {
3123
		var filesaver = this;
3124
		filesaver.readyState = filesaver.DONE;
3125
		dispatch(filesaver, "abort");
3126
	};
3127
	FS_proto.readyState = FS_proto.INIT = 0;
3128
	FS_proto.WRITING = 1;
3129
	FS_proto.DONE = 2;
3130
	
3131
	FS_proto.error =
3132
	FS_proto.onwritestart =
3133
	FS_proto.onprogress =
3134
	FS_proto.onwrite =
3135
	FS_proto.onabort =
3136
	FS_proto.onerror =
3137
	FS_proto.onwriteend =
3138
		null;
3139
	
3140
	view.addEventListener("unload", process_deletion_queue, false);
3141
	return saveAs;
3142
}(self));
3143
3144
/**@preserve
3145
 *  ==================================================================== 
3146
 * jsPDF [NAME] plugin
3147
 * Copyright (c) 2014 James Robb, https://github.com/jamesbrobb
3148
 * 
3149
 * Permission is hereby granted, free of charge, to any person obtaining
3150
 * a copy of this software and associated documentation files (the
3151
 * "Software"), to deal in the Software without restriction, including
3152
 * without limitation the rights to use, copy, modify, merge, publish,
3153
 * distribute, sublicense, and/or sell copies of the Software, and to
3154
 * permit persons to whom the Software is furnished to do so, subject to
3155
 * the following conditions:
3156
 * 
3157
 * The above copyright notice and this permission notice shall be
3158
 * included in all copies or substantial portions of the Software.
3159
 * 
3160
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
3161
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
3162
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
3163
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
3164
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
3165
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
3166
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3167
 * ====================================================================
3168
 */
3169
3170
(function(jsPDFAPI) {
3171
'use strict'
3172
	
3173
	/*
3174
	 * @see http://www.w3.org/TR/PNG-Chunks.html
3175
	 * 
3176
	 Color    Allowed      Interpretation
3177
	 Type     Bit Depths
3178
	   
3179
	   0       1,2,4,8,16  Each pixel is a grayscale sample.
3180
	   
3181
	   2       8,16        Each pixel is an R,G,B triple.
3182
	   
3183
	   3       1,2,4,8     Each pixel is a palette index;
3184
	                       a PLTE chunk must appear.
3185
	   
3186
	   4       8,16        Each pixel is a grayscale sample,
3187
	                       followed by an alpha sample.
3188
	   
3189
	   6       8,16        Each pixel is an R,G,B triple,
3190
	                       followed by an alpha sample.
3191
	*/
3192
	
3193
	/*
3194
	 * PNG filter method types
3195
	 * 
3196
	 * @see http://www.w3.org/TR/PNG-Filters.html
3197
	 * @see http://www.libpng.org/pub/png/book/chapter09.html
3198
	 * 
3199
	 * This is what the value 'Predictor' in decode params relates to
3200
	 * 
3201
	 * 15 is "optimal prediction", which means the prediction algorithm can change from line to line.
3202
	 * In that case, you actually have to read the first byte off each line for the prediction algorthim (which should be 0-4, corresponding to PDF 10-14) and select the appropriate unprediction algorithm based on that byte.
3203
	 *
3204
	   0       None
3205
	   1       Sub
3206
	   2       Up
3207
	   3       Average
3208
	   4       Paeth
3209
	 */
3210
	
3211
	var doesNotHavePngJS = function() {
3212
		return typeof PNG !== 'function' || typeof FlateStream !== 'function';
0 ignored issues
show
Bug introduced by
The variable PNG seems to be never declared. If this is a global, consider adding a /** global: PNG */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
3213
	}
3214
	, canCompress = function(value) {
3215
		return value !== jsPDFAPI.image_compression.NONE && hasCompressionJS();
3216
	}
3217
	, hasCompressionJS = function() {
3218
		var inst = typeof Deflater === 'function';
3219
		if(!inst)
3220
			throw new Error("requires deflate.js for compression")
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3221
		return inst;
3222
	}
3223
	, compressBytes = function(bytes, lineLength, colorsPerPixel, compression) {
3224
		
3225
		var level = 5,
3226
			filter_method = filterUp;
3227
		
3228
		switch(compression) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3229
		
3230
			case jsPDFAPI.image_compression.FAST:
0 ignored issues
show
Bug introduced by
The variable jsPDFAPI seems to be never declared. If this is a global, consider adding a /** global: jsPDFAPI */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
3231
				
3232
				level = 3;
3233
				filter_method = filterSub;
3234
				break;
3235
				
3236
			case jsPDFAPI.image_compression.MEDIUM:
3237
				
3238
				level = 6;
3239
				filter_method = filterAverage;
3240
				break;
3241
				
3242
			case jsPDFAPI.image_compression.SLOW:
3243
				
3244
				level = 9;
3245
				filter_method = filterPaeth;//uses to sum to choose best filter for each line
3246
				break;
3247
		}
3248
		
3249
		bytes = applyPngFilterMethod(bytes, lineLength, colorsPerPixel, filter_method);
3250
		
3251
		var header = new Uint8Array(createZlibHeader(level));
3252
		var checksum = adler32(bytes);
3253
		
3254
		var deflate = new Deflater(level);
3255
		var a = deflate.append(bytes);
3256
		var cBytes = deflate.flush();
3257
		
3258
		var len = header.length + a.length + cBytes.length;
3259
		
3260
		var cmpd = new Uint8Array(len + 4);
3261
		cmpd.set(header);
3262
		cmpd.set(a, header.length);
3263
		cmpd.set(cBytes, header.length + a.length);
3264
		
3265
		cmpd[len++] = (checksum >>> 24) & 0xff;
3266
		cmpd[len++] = (checksum >>> 16) & 0xff;
3267
		cmpd[len++] = (checksum >>> 8) & 0xff;
3268
		cmpd[len++] = checksum & 0xff;
0 ignored issues
show
Unused Code introduced by
The assignment to variable len seems to be never used. Consider removing it.
Loading history...
3269
		
3270
		return jsPDFAPI.arrayBufferToBinaryString(cmpd);
3271
	}
3272
	, createZlibHeader = function(bytes, level){
3273
		/*
3274
		 * @see http://www.ietf.org/rfc/rfc1950.txt for zlib header 
3275
		 */
3276
		var cm = 8;
3277
        var cinfo = Math.LOG2E * Math.log(0x8000) - 8;
3278
        var cmf = (cinfo << 4) | cm;
3279
        
3280
        var hdr = cmf << 8;
3281
        var flevel = Math.min(3, ((level - 1) & 0xff) >> 1);
3282
        
3283
        hdr |= (flevel << 6);
3284
        hdr |= 0;//FDICT
3285
        hdr += 31 - (hdr % 31);
3286
        
3287
        return [cmf, (hdr & 0xff) & 0xff];
3288
	}
3289
	, adler32 = function(array, param) {
3290
		var adler = 1;
3291
	    var s1 = adler & 0xffff,
3292
	        s2 = (adler >>> 16) & 0xffff;
3293
	    var len = array.length;
3294
	    var tlen;
3295
	    var i = 0;
3296
3297
	    while (len > 0) {
3298
	      tlen = len > param ? param : len;
3299
	      len -= tlen;
3300
	      do {
3301
	        s1 += array[i++];
3302
	        s2 += s1;
3303
	      } while (--tlen);
3304
3305
	      s1 %= 65521;
3306
	      s2 %= 65521;
3307
	    }
3308
3309
	    return ((s2 << 16) | s1) >>> 0;
3310
	}
3311
	, applyPngFilterMethod = function(bytes, lineLength, colorsPerPixel, filter_method) {
3312
		var lines = bytes.length / lineLength,
3313
			result = new Uint8Array(bytes.length + lines),
3314
			filter_methods = getFilterMethods(),
3315
			i = 0, line, prevLine, offset;
3316
		
3317
		for(; i < lines; i++) {
3318
			offset = i * lineLength;
3319
			line = bytes.subarray(offset, offset + lineLength);
3320
			
3321
			if(filter_method) {
3322
				result.set(filter_method(line, colorsPerPixel, prevLine), offset + i);
0 ignored issues
show
Bug introduced by
The variable prevLine seems to not be initialized for all possible execution paths. Are you sure filter_method handles undefined variables?
Loading history...
3323
				
3324
			}else{
3325
			
3326
				var j = 0,
3327
					len = filter_methods.length,
3328
					results = [];
3329
				
3330
				for(; j < len; j++)
3331
					results[j] = filter_methods[j](line, colorsPerPixel, prevLine);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3332
				
3333
				var ind = getIndexOfSmallestSum(results.concat());
3334
				
3335
				result.set(results[ind], offset + i);
3336
			}
3337
			
3338
			prevLine = line;
3339
		}
3340
		
3341
		return result;
3342
	}
3343
	, filterNone = function(line, colorsPerPixel, prevLine) {
0 ignored issues
show
Unused Code introduced by
The parameter colorsPerPixel is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter prevLine is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
3344
		/*var result = new Uint8Array(line.length + 1);
3345
		result[0] = 0;
3346
		result.set(line, 1);*/
3347
		
3348
		var result = Array.apply([], line);
3349
		result.unshift(0);
3350
3351
		return result;
3352
	}
3353
	, filterSub = function(line, colorsPerPixel, prevLine) {
0 ignored issues
show
Unused Code introduced by
The parameter prevLine is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
3354
		var result = [],
3355
			i = 0,
3356
			len = line.length,
3357
			left;
3358
		
3359
		result[0] = 1;
3360
		
3361
		for(; i < len; i++) {
3362
			left = line[i - colorsPerPixel] || 0;
3363
			result[i + 1] = (line[i] - left + 0x0100) & 0xff;
3364
		}
3365
		
3366
		return result;
3367
	}
3368
	, filterUp = function(line, colorsPerPixel, prevLine) {
3369
		var result = [],
3370
			i = 0,
3371
			len = line.length,
3372
			up;
3373
		
3374
		result[0] = 2;
3375
		
3376
		for(; i < len; i++) {
3377
			up = prevLine && prevLine[i] || 0;
3378
			result[i + 1] = (line[i] - up + 0x0100) & 0xff;
3379
		}
3380
		
3381
		return result;
3382
	}
3383
	, filterAverage = function(line, colorsPerPixel, prevLine) {
3384
		var result = [],
3385
			i = 0,
3386
			len = line.length,
3387
			left,
3388
			up;
3389
	
3390
		result[0] = 3;
3391
		
3392
		for(; i < len; i++) {
3393
			left = line[i - colorsPerPixel] || 0;
3394
			up = prevLine && prevLine[i] || 0;
3395
			result[i + 1] = (line[i] + 0x0100 - ((left + up) >>> 1)) & 0xff;
3396
		}
3397
		
3398
		return result;
3399
	}
3400
	, filterPaeth = function(line, colorsPerPixel, prevLine) {
3401
		var result = [],
3402
			i = 0,
3403
			len = line.length,
3404
			left,
3405
			up,
3406
			upLeft,
3407
			paeth;
3408
		
3409
		result[0] = 4;
3410
		
3411
		for(; i < len; i++) {
3412
			left = line[i - colorsPerPixel] || 0;
3413
			up = prevLine && prevLine[i] || 0;
3414
			upLeft = prevLine && prevLine[i - colorsPerPixel] || 0;
3415
			paeth = paethPredictor(left, up, upLeft);
3416
			result[i + 1] = (line[i] - paeth + 0x0100) & 0xff;
3417
		}
3418
		
3419
		return result;
3420
	}
3421
	,paethPredictor = function(left, up, upLeft) {
3422
3423
		var p = left + up - upLeft,
3424
	        pLeft = Math.abs(p - left),
3425
	        pUp = Math.abs(p - up),
3426
	        pUpLeft = Math.abs(p - upLeft);
3427
		
3428
		return (pLeft <= pUp && pLeft <= pUpLeft) ? left : (pUp <= pUpLeft) ? up : upLeft;
3429
	}
3430
	, getFilterMethods = function() {
3431
		return [filterNone, filterSub, filterUp, filterAverage, filterPaeth];
3432
	}
3433
	,getIndexOfSmallestSum = function(arrays) {
3434
		var i = 0,
3435
			len = arrays.length,
3436
			sum, min, ind;
3437
		
3438
		while(i < len) {
3439
			sum = absSum(arrays[i].slice(1));
3440
			
3441
			if(sum < min || !min) {
0 ignored issues
show
Comprehensibility Bug introduced by
The variable min does not seem to be initialized in case the while loop on line 3438 is not entered. Are you sure this can never be the case?
Loading history...
3442
				min = sum;
3443
				ind = i;
3444
			}
3445
			
3446
			i++;
3447
		}
3448
		
3449
		return ind;
0 ignored issues
show
Bug introduced by
The variable ind seems to not be initialized for all possible execution paths.
Loading history...
3450
	}
3451
	, absSum = function(array) {
3452
		var i = 0,
3453
			len = array.length,
3454
			sum = 0;
3455
	
3456
		while(i < len)
3457
			sum += Math.abs(array[i++]);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3458
			
3459
		return sum;
3460
	}
3461
	, logImg = function(img) {
0 ignored issues
show
Unused Code introduced by
The variable logImg seems to be never used. Consider removing it.
Loading history...
3462
		console.log("width: " + img.width);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
3463
		console.log("height: " + img.height);
3464
		console.log("bits: " + img.bits);
3465
		console.log("colorType: " + img.colorType);
3466
		console.log("transparency:");
3467
		console.log(img.transparency);
3468
		console.log("text:");
3469
		console.log(img.text);
3470
		console.log("compressionMethod: " + img.compressionMethod);
3471
		console.log("filterMethod: " + img.filterMethod);
3472
		console.log("interlaceMethod: " + img.interlaceMethod);
3473
		console.log("imgData:");
3474
		console.log(img.imgData);
3475
		console.log("palette:");
3476
		console.log(img.palette);
3477
		console.log("colors: " + img.colors);
3478
		console.log("colorSpace: " + img.colorSpace);
3479
		console.log("pixelBitlength: " + img.pixelBitlength);
3480
		console.log("hasAlphaChannel: " + img.hasAlphaChannel);
3481
	};
3482
	
3483
	
3484
	
3485
	
3486
	jsPDFAPI.processPNG = function(imageData, imageIndex, alias, compression, dataAsBinaryString) {
0 ignored issues
show
Unused Code introduced by
The parameter dataAsBinaryString is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
3487
		'use strict'
3488
		
3489
		var colorSpace = this.color_spaces.DEVICE_RGB,
3490
			decode = this.decode.FLATE_DECODE,
3491
			bpc = 8,
0 ignored issues
show
Unused Code introduced by
The assignment to variable bpc seems to be never used. Consider removing it.
Loading history...
3492
			img, dp, trns,
3493
			colors, pal, smask;
3494
		
3495
		if(this.isString(imageData)) {
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
3496
			
3497
		}
3498
		
3499
		if(this.isArrayBuffer(imageData))
3500
			imageData = new Uint8Array(imageData);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3501
		
3502
		if(this.isArrayBufferView(imageData)) {
3503
			
3504
			if(doesNotHavePngJS())
3505
				throw new Error("PNG support requires png.js and zlib.js");
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3506
				
3507
			img = new PNG(imageData);
0 ignored issues
show
Bug introduced by
The variable PNG seems to be never declared. If this is a global, consider adding a /** global: PNG */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
3508
			imageData = img.imgData;
3509
			bpc = img.bits;
3510
			colorSpace = img.colorSpace;
3511
			colors = img.colors;
3512
			
3513
			//logImg(img);
3514
			
3515
			/*
3516
			 * colorType 6 - Each pixel is an R,G,B triple, followed by an alpha sample.
3517
			 * 
3518
			 * colorType 4 - Each pixel is a grayscale sample, followed by an alpha sample.
3519
			 * 
3520
			 * Extract alpha to create two separate images, using the alpha as a sMask
3521
			 */
3522
			if([4,6].indexOf(img.colorType) !== -1) {
3523
				
3524
				/*
3525
				 * processes 8 bit RGBA and grayscale + alpha images
3526
				 */
3527 View Code Duplication
				if(img.bits === 8) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
3528
				
3529
					var pixelsArrayType = window['Uint' + img.pixelBitlength + 'Array'],
3530
						pixels = new pixelsArrayType(img.decodePixels().buffer),
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like pixelsArrayType should be capitalized.
Loading history...
3531
						len = pixels.length,
3532
						imgData = new Uint8Array(len * img.colors),
3533
						alphaData = new Uint8Array(len),
3534
						pDiff = img.pixelBitlength - img.bits,
3535
						i = 0, n = 0, pixel, pbl;
3536
				
3537
					for(; i < len; i++) {
3538
						pixel = pixels[i];
3539
						pbl = 0;
3540
						
3541
						while(pbl < pDiff) {
3542
							
3543
							imgData[n++] = ( pixel >>> pbl ) & 0xff;
3544
							pbl = pbl + img.bits;
3545
						}
3546
						
3547
						alphaData[i] = ( pixel >>> pbl ) & 0xff;
3548
					}
3549
				}
3550
				
3551
				/*
3552
				 * processes 16 bit RGBA and grayscale + alpha images
3553
				 */
3554 View Code Duplication
				if(img.bits === 16) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
3555
					
3556
					var pixels = new Uint32Array(img.decodePixels().buffer),
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable pixels already seems to be declared on line 3530. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3557
						len = pixels.length,
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable len already seems to be declared on line 3531. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3558
						imgData = new Uint8Array((len * (32 / img.pixelBitlength) ) * img.colors),
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable imgData already seems to be declared on line 3532. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3559
						alphaData = new Uint8Array(len * (32 / img.pixelBitlength) ),
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable alphaData already seems to be declared on line 3533. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3560
						hasColors = img.colors > 1,
3561
						i = 0, n = 0, a = 0, pixel;
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable n already seems to be declared on line 3535. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
Comprehensibility Naming Best Practice introduced by
The variable pixel already seems to be declared on line 3535. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
Comprehensibility Naming Best Practice introduced by
The variable i already seems to be declared on line 3535. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3562
					
3563
					while(i < len) {
3564
						pixel = pixels[i++];
3565
						
3566
						imgData[n++] = (pixel >>> 0) & 0xFF;
3567
						
3568
						if(hasColors) {
3569
							imgData[n++] = (pixel >>> 16) & 0xFF;
3570
							
3571
							pixel = pixels[i++];
3572
							imgData[n++] = (pixel >>> 0) & 0xFF;
3573
						}
3574
						
3575
						alphaData[a++] = (pixel >>> 16) & 0xFF;
3576
					}
3577
					
3578
					bpc = 8;
3579
				}
3580
				
3581
				if(canCompress(compression)) {
3582
										
3583
					imageData = compressBytes(imgData, img.width * img.colors, img.colors, compression);
0 ignored issues
show
Bug introduced by
The variable imgData does not seem to be initialized in case img.bits === 8 on line 3527 is false. Are you sure the function compressBytes handles undefined variables?
Loading history...
3584
					smask = compressBytes(alphaData, img.width, 1, compression);
0 ignored issues
show
Bug introduced by
The variable alphaData does not seem to be initialized in case img.bits === 8 on line 3527 is false. Are you sure the function compressBytes handles undefined variables?
Loading history...
3585
					
3586
				}else{
3587
					
3588
					imageData = imgData;
3589
					smask = alphaData;
3590
					decode = null;
3591
				}
3592
			}
3593
			
3594
			/*
3595
			 * Indexed png. Each pixel is a palette index.
3596
			 */
3597
			if(img.colorType === 3) {
3598
				
3599
				colorSpace = this.color_spaces.INDEXED;
3600
				pal = img.palette;
3601
				
3602
				if(img.transparency.indexed) {
3603
					
3604
					var trans = img.transparency.indexed;
3605
					
3606
					var total = 0,
3607
						i = 0,
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable i already seems to be declared on line 3535. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3608
						len = trans.length;
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable len already seems to be declared on line 3531. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3609
3610
					for(; i<len; ++i)
3611
					    total += trans[i];
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3612
					
3613
					total = total / 255;
3614
					
3615
					/*
3616
					 * a single color is specified as 100% transparent (0),
3617
					 * so we set trns to use a /Mask with that index
3618
					 */
3619
					if(total === len - 1 && trans.indexOf(0) !== -1) {
3620
						trns = [trans.indexOf(0)];
3621
					
3622
					/*
3623
					 * there's more than one colour within the palette that specifies
3624
					 * a transparency value less than 255, so we unroll the pixels to create an image sMask
3625
					 */
3626
					}else if(total !== len){
3627
						
3628
						var pixels = img.decodePixels(),
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable pixels already seems to be declared on line 3530. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3629
							alphaData = new Uint8Array(pixels.length),
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable alphaData already seems to be declared on line 3533. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3630
							i = 0,
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable i already seems to be declared on line 3535. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3631
							len = pixels.length;
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable len already seems to be declared on line 3531. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3632
						
3633
						for(; i < len; i++)
3634
							alphaData[i] = trans[pixels[i]];
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3635
						
3636
						smask = compressBytes(alphaData, img.width, 1);
3637
					}
3638
				}
3639
			}
3640
			
3641
			if(decode === this.decode.FLATE_DECODE)
3642
				dp = '/Predictor 15 /Colors '+ colors +' /BitsPerComponent '+ bpc +' /Columns '+ img.width;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3643
			else
3644
				//remove 'Predictor' as it applies to the type of png filter applied to its IDAT - we only apply with compression
3645
				dp = '/Colors '+ colors +' /BitsPerComponent '+ bpc +' /Columns '+ img.width;
3646
			
3647
			if(this.isArrayBuffer(imageData) || this.isArrayBufferView(imageData))
3648
				imageData = this.arrayBufferToBinaryString(imageData);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3649
			
3650
			if(smask && this.isArrayBuffer(smask) || this.isArrayBufferView(smask))
0 ignored issues
show
Bug introduced by
The variable smask does not seem to be initialized in case [4, 6].indexOf(img.colorType) !== -1 on line 3522 is false. Are you sure the function isArrayBufferView handles undefined variables?
Loading history...
3651
				smask = this.arrayBufferToBinaryString(smask);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3652
			
3653
			return this.createImageInfo(imageData, img.width, img.height, colorSpace,
3654
										bpc, decode, imageIndex, alias, dp, trns, pal, smask);
0 ignored issues
show
Bug introduced by
The variable pal does not seem to be initialized in case img.colorType === 3 on line 3597 is false. Are you sure the function createImageInfo handles undefined variables?
Loading history...
Bug introduced by
The variable trns seems to not be initialized for all possible execution paths. Are you sure createImageInfo handles undefined variables?
Loading history...
3655
		}
3656
		
3657
		return info;
0 ignored issues
show
Bug introduced by
The variable info seems to be never declared. If this is a global, consider adding a /** global: info */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
3658
	}
3659
3660
})(jsPDF.API)
3661
3662
/*
3663
 * Extracted from pdf.js
3664
 * https://github.com/andreasgal/pdf.js
3665
 *
3666
 * Copyright (c) 2011 Mozilla Foundation
3667
 *
3668
 * Contributors: Andreas Gal <[email protected]>
3669
 *               Chris G Jones <[email protected]>
3670
 *               Shaon Barman <[email protected]>
3671
 *               Vivien Nicolas <[email protected]>
3672
 *               Justin D'Arcangelo <[email protected]>
3673
 *               Yury Delendik
3674
 *
3675
 * Permission is hereby granted, free of charge, to any person obtaining a
3676
 * copy of this software and associated documentation files (the "Software"),
3677
 * to deal in the Software without restriction, including without limitation
3678
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
3679
 * and/or sell copies of the Software, and to permit persons to whom the
3680
 * Software is furnished to do so, subject to the following conditions:
3681
 *
3682
 * The above copyright notice and this permission notice shall be included in
3683
 * all copies or substantial portions of the Software.
3684
 *
3685
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3686
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3687
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
3688
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3689
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
3690
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
3691
 * DEALINGS IN THE SOFTWARE.
3692
 */
3693
3694
var DecodeStream = (function() {
3695
  function constructor() {
3696
    this.pos = 0;
3697
    this.bufferLength = 0;
3698
    this.eof = false;
3699
    this.buffer = null;
3700
  }
3701
3702
  constructor.prototype = {
3703
    ensureBuffer: function decodestream_ensureBuffer(requested) {
3704
      var buffer = this.buffer;
3705
      var current = buffer ? buffer.byteLength : 0;
3706
      if (requested < current)
3707
        return buffer;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3708
      var size = 512;
3709
      while (size < requested)
3710
        size <<= 1;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3711
      var buffer2 = new Uint8Array(size);
3712
      for (var i = 0; i < current; ++i)
3713
        buffer2[i] = buffer[i];
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3714
      return this.buffer = buffer2;
3715
    },
3716
    getByte: function decodestream_getByte() {
3717
      var pos = this.pos;
3718
      while (this.bufferLength <= pos) {
3719
        if (this.eof)
3720
          return null;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3721
        this.readBlock();
3722
      }
3723
      return this.buffer[this.pos++];
3724
    },
3725
    getBytes: function decodestream_getBytes(length) {
3726
      var pos = this.pos;
3727
3728
      if (length) {
3729
        this.ensureBuffer(pos + length);
3730
        var end = pos + length;
3731
3732
        while (!this.eof && this.bufferLength < end)
3733
          this.readBlock();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3734
3735
        var bufEnd = this.bufferLength;
3736
        if (end > bufEnd)
3737
          end = bufEnd;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3738
      } else {
3739
        while (!this.eof)
3740
          this.readBlock();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3741
3742
        var end = this.bufferLength;
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable end already seems to be declared on line 3730. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3743
      }
3744
3745
      this.pos = end;
3746
      return this.buffer.subarray(pos, end);
3747
    },
3748
    lookChar: function decodestream_lookChar() {
3749
      var pos = this.pos;
3750
      while (this.bufferLength <= pos) {
3751
        if (this.eof)
3752
          return null;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3753
        this.readBlock();
3754
      }
3755
      return String.fromCharCode(this.buffer[this.pos]);
3756
    },
3757
    getChar: function decodestream_getChar() {
3758
      var pos = this.pos;
3759
      while (this.bufferLength <= pos) {
3760
        if (this.eof)
3761
          return null;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3762
        this.readBlock();
3763
      }
3764
      return String.fromCharCode(this.buffer[this.pos++]);
3765
    },
3766
    makeSubStream: function decodestream_makeSubstream(start, length, dict) {
3767
      var end = start + length;
3768
      while (this.bufferLength <= end && !this.eof)
3769
        this.readBlock();
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3770
      return new Stream(this.buffer, start, length, dict);
0 ignored issues
show
Bug introduced by
The variable Stream seems to be never declared. If this is a global, consider adding a /** global: Stream */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
3771
    },
3772
    skip: function decodestream_skip(n) {
3773
      if (!n)
3774
        n = 1;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3775
      this.pos += n;
3776
    },
3777
    reset: function decodestream_reset() {
3778
      this.pos = 0;
3779
    }
3780
  };
3781
3782
  return constructor;
3783
})();
3784
3785
var FlateStream = (function() {
3786
  var codeLenCodeMap = new Uint32Array([
3787
    16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
3788
  ]);
3789
3790
  var lengthDecode = new Uint32Array([
3791
    0x00003, 0x00004, 0x00005, 0x00006, 0x00007, 0x00008, 0x00009, 0x0000a,
3792
    0x1000b, 0x1000d, 0x1000f, 0x10011, 0x20013, 0x20017, 0x2001b, 0x2001f,
3793
    0x30023, 0x3002b, 0x30033, 0x3003b, 0x40043, 0x40053, 0x40063, 0x40073,
3794
    0x50083, 0x500a3, 0x500c3, 0x500e3, 0x00102, 0x00102, 0x00102
3795
  ]);
3796
3797
  var distDecode = new Uint32Array([
3798
    0x00001, 0x00002, 0x00003, 0x00004, 0x10005, 0x10007, 0x20009, 0x2000d,
3799
    0x30011, 0x30019, 0x40021, 0x40031, 0x50041, 0x50061, 0x60081, 0x600c1,
3800
    0x70101, 0x70181, 0x80201, 0x80301, 0x90401, 0x90601, 0xa0801, 0xa0c01,
3801
    0xb1001, 0xb1801, 0xc2001, 0xc3001, 0xd4001, 0xd6001
3802
  ]);
3803
3804
  var fixedLitCodeTab = [new Uint32Array([
3805
    0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c0,
3806
    0x70108, 0x80060, 0x80020, 0x900a0, 0x80000, 0x80080, 0x80040, 0x900e0,
3807
    0x70104, 0x80058, 0x80018, 0x90090, 0x70114, 0x80078, 0x80038, 0x900d0,
3808
    0x7010c, 0x80068, 0x80028, 0x900b0, 0x80008, 0x80088, 0x80048, 0x900f0,
3809
    0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c8,
3810
    0x7010a, 0x80064, 0x80024, 0x900a8, 0x80004, 0x80084, 0x80044, 0x900e8,
3811
    0x70106, 0x8005c, 0x8001c, 0x90098, 0x70116, 0x8007c, 0x8003c, 0x900d8,
3812
    0x7010e, 0x8006c, 0x8002c, 0x900b8, 0x8000c, 0x8008c, 0x8004c, 0x900f8,
3813
    0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c4,
3814
    0x70109, 0x80062, 0x80022, 0x900a4, 0x80002, 0x80082, 0x80042, 0x900e4,
3815
    0x70105, 0x8005a, 0x8001a, 0x90094, 0x70115, 0x8007a, 0x8003a, 0x900d4,
3816
    0x7010d, 0x8006a, 0x8002a, 0x900b4, 0x8000a, 0x8008a, 0x8004a, 0x900f4,
3817
    0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cc,
3818
    0x7010b, 0x80066, 0x80026, 0x900ac, 0x80006, 0x80086, 0x80046, 0x900ec,
3819
    0x70107, 0x8005e, 0x8001e, 0x9009c, 0x70117, 0x8007e, 0x8003e, 0x900dc,
3820
    0x7010f, 0x8006e, 0x8002e, 0x900bc, 0x8000e, 0x8008e, 0x8004e, 0x900fc,
3821
    0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c2,
3822
    0x70108, 0x80061, 0x80021, 0x900a2, 0x80001, 0x80081, 0x80041, 0x900e2,
3823
    0x70104, 0x80059, 0x80019, 0x90092, 0x70114, 0x80079, 0x80039, 0x900d2,
3824
    0x7010c, 0x80069, 0x80029, 0x900b2, 0x80009, 0x80089, 0x80049, 0x900f2,
3825
    0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900ca,
3826
    0x7010a, 0x80065, 0x80025, 0x900aa, 0x80005, 0x80085, 0x80045, 0x900ea,
3827
    0x70106, 0x8005d, 0x8001d, 0x9009a, 0x70116, 0x8007d, 0x8003d, 0x900da,
3828
    0x7010e, 0x8006d, 0x8002d, 0x900ba, 0x8000d, 0x8008d, 0x8004d, 0x900fa,
3829
    0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c6,
3830
    0x70109, 0x80063, 0x80023, 0x900a6, 0x80003, 0x80083, 0x80043, 0x900e6,
3831
    0x70105, 0x8005b, 0x8001b, 0x90096, 0x70115, 0x8007b, 0x8003b, 0x900d6,
3832
    0x7010d, 0x8006b, 0x8002b, 0x900b6, 0x8000b, 0x8008b, 0x8004b, 0x900f6,
3833
    0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900ce,
3834
    0x7010b, 0x80067, 0x80027, 0x900ae, 0x80007, 0x80087, 0x80047, 0x900ee,
3835
    0x70107, 0x8005f, 0x8001f, 0x9009e, 0x70117, 0x8007f, 0x8003f, 0x900de,
3836
    0x7010f, 0x8006f, 0x8002f, 0x900be, 0x8000f, 0x8008f, 0x8004f, 0x900fe,
3837
    0x70100, 0x80050, 0x80010, 0x80118, 0x70110, 0x80070, 0x80030, 0x900c1,
3838
    0x70108, 0x80060, 0x80020, 0x900a1, 0x80000, 0x80080, 0x80040, 0x900e1,
3839
    0x70104, 0x80058, 0x80018, 0x90091, 0x70114, 0x80078, 0x80038, 0x900d1,
3840
    0x7010c, 0x80068, 0x80028, 0x900b1, 0x80008, 0x80088, 0x80048, 0x900f1,
3841
    0x70102, 0x80054, 0x80014, 0x8011c, 0x70112, 0x80074, 0x80034, 0x900c9,
3842
    0x7010a, 0x80064, 0x80024, 0x900a9, 0x80004, 0x80084, 0x80044, 0x900e9,
3843
    0x70106, 0x8005c, 0x8001c, 0x90099, 0x70116, 0x8007c, 0x8003c, 0x900d9,
3844
    0x7010e, 0x8006c, 0x8002c, 0x900b9, 0x8000c, 0x8008c, 0x8004c, 0x900f9,
3845
    0x70101, 0x80052, 0x80012, 0x8011a, 0x70111, 0x80072, 0x80032, 0x900c5,
3846
    0x70109, 0x80062, 0x80022, 0x900a5, 0x80002, 0x80082, 0x80042, 0x900e5,
3847
    0x70105, 0x8005a, 0x8001a, 0x90095, 0x70115, 0x8007a, 0x8003a, 0x900d5,
3848
    0x7010d, 0x8006a, 0x8002a, 0x900b5, 0x8000a, 0x8008a, 0x8004a, 0x900f5,
3849
    0x70103, 0x80056, 0x80016, 0x8011e, 0x70113, 0x80076, 0x80036, 0x900cd,
3850
    0x7010b, 0x80066, 0x80026, 0x900ad, 0x80006, 0x80086, 0x80046, 0x900ed,
3851
    0x70107, 0x8005e, 0x8001e, 0x9009d, 0x70117, 0x8007e, 0x8003e, 0x900dd,
3852
    0x7010f, 0x8006e, 0x8002e, 0x900bd, 0x8000e, 0x8008e, 0x8004e, 0x900fd,
3853
    0x70100, 0x80051, 0x80011, 0x80119, 0x70110, 0x80071, 0x80031, 0x900c3,
3854
    0x70108, 0x80061, 0x80021, 0x900a3, 0x80001, 0x80081, 0x80041, 0x900e3,
3855
    0x70104, 0x80059, 0x80019, 0x90093, 0x70114, 0x80079, 0x80039, 0x900d3,
3856
    0x7010c, 0x80069, 0x80029, 0x900b3, 0x80009, 0x80089, 0x80049, 0x900f3,
3857
    0x70102, 0x80055, 0x80015, 0x8011d, 0x70112, 0x80075, 0x80035, 0x900cb,
3858
    0x7010a, 0x80065, 0x80025, 0x900ab, 0x80005, 0x80085, 0x80045, 0x900eb,
3859
    0x70106, 0x8005d, 0x8001d, 0x9009b, 0x70116, 0x8007d, 0x8003d, 0x900db,
3860
    0x7010e, 0x8006d, 0x8002d, 0x900bb, 0x8000d, 0x8008d, 0x8004d, 0x900fb,
3861
    0x70101, 0x80053, 0x80013, 0x8011b, 0x70111, 0x80073, 0x80033, 0x900c7,
3862
    0x70109, 0x80063, 0x80023, 0x900a7, 0x80003, 0x80083, 0x80043, 0x900e7,
3863
    0x70105, 0x8005b, 0x8001b, 0x90097, 0x70115, 0x8007b, 0x8003b, 0x900d7,
3864
    0x7010d, 0x8006b, 0x8002b, 0x900b7, 0x8000b, 0x8008b, 0x8004b, 0x900f7,
3865
    0x70103, 0x80057, 0x80017, 0x8011f, 0x70113, 0x80077, 0x80037, 0x900cf,
3866
    0x7010b, 0x80067, 0x80027, 0x900af, 0x80007, 0x80087, 0x80047, 0x900ef,
3867
    0x70107, 0x8005f, 0x8001f, 0x9009f, 0x70117, 0x8007f, 0x8003f, 0x900df,
3868
    0x7010f, 0x8006f, 0x8002f, 0x900bf, 0x8000f, 0x8008f, 0x8004f, 0x900ff
3869
  ]), 9];
3870
3871
  var fixedDistCodeTab = [new Uint32Array([
3872
    0x50000, 0x50010, 0x50008, 0x50018, 0x50004, 0x50014, 0x5000c, 0x5001c,
3873
    0x50002, 0x50012, 0x5000a, 0x5001a, 0x50006, 0x50016, 0x5000e, 0x00000,
3874
    0x50001, 0x50011, 0x50009, 0x50019, 0x50005, 0x50015, 0x5000d, 0x5001d,
3875
    0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000
3876
  ]), 5];
3877
  
3878
  function error(e) {
3879
      throw new Error(e)
3880
  }
3881
3882
  function constructor(bytes) {
3883
    //var bytes = stream.getBytes();
3884
    var bytesPos = 0;
3885
3886
    var cmf = bytes[bytesPos++];
3887
    var flg = bytes[bytesPos++];
3888
    if (cmf == -1 || flg == -1)
3889
      error('Invalid header in flate stream');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3890
    if ((cmf & 0x0f) != 0x08)
3891
      error('Unknown compression method in flate stream');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3892
    if ((((cmf << 8) + flg) % 31) != 0)
3893
      error('Bad FCHECK in flate stream');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3894
    if (flg & 0x20)
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
3895
      error('FDICT bit set in flate stream');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3896
3897
    this.bytes = bytes;
3898
    this.bytesPos = bytesPos;
3899
3900
    this.codeSize = 0;
3901
    this.codeBuf = 0;
3902
3903
    DecodeStream.call(this);
3904
  }
3905
3906
  constructor.prototype = Object.create(DecodeStream.prototype);
3907
3908
  constructor.prototype.getBits = function(bits) {
3909
    var codeSize = this.codeSize;
3910
    var codeBuf = this.codeBuf;
3911
    var bytes = this.bytes;
3912
    var bytesPos = this.bytesPos;
3913
3914
    var b;
3915
    while (codeSize < bits) {
3916
      if (typeof (b = bytes[bytesPos++]) == 'undefined')
3917
        error('Bad encoding in flate stream');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3918
      codeBuf |= b << codeSize;
3919
      codeSize += 8;
3920
    }
3921
    b = codeBuf & ((1 << bits) - 1);
3922
    this.codeBuf = codeBuf >> bits;
3923
    this.codeSize = codeSize -= bits;
3924
    this.bytesPos = bytesPos;
3925
    return b;
3926
  };
3927
3928
  constructor.prototype.getCode = function(table) {
3929
    var codes = table[0];
3930
    var maxLen = table[1];
3931
    var codeSize = this.codeSize;
3932
    var codeBuf = this.codeBuf;
3933
    var bytes = this.bytes;
3934
    var bytesPos = this.bytesPos;
3935
3936
    while (codeSize < maxLen) {
3937
      var b;
3938
      if (typeof (b = bytes[bytesPos++]) == 'undefined')
3939
        error('Bad encoding in flate stream');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3940
      codeBuf |= (b << codeSize);
3941
      codeSize += 8;
3942
    }
3943
    var code = codes[codeBuf & ((1 << maxLen) - 1)];
3944
    var codeLen = code >> 16;
3945
    var codeVal = code & 0xffff;
3946
    if (codeSize == 0 || codeSize < codeLen || codeLen == 0)
3947
      error('Bad encoding in flate stream');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3948
    this.codeBuf = (codeBuf >> codeLen);
3949
    this.codeSize = (codeSize - codeLen);
3950
    this.bytesPos = bytesPos;
3951
    return codeVal;
3952
  };
3953
3954
  constructor.prototype.generateHuffmanTable = function(lengths) {
3955
    var n = lengths.length;
3956
3957
    // find max code length
3958
    var maxLen = 0;
3959
    for (var i = 0; i < n; ++i) {
3960
      if (lengths[i] > maxLen)
3961
        maxLen = lengths[i];
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3962
    }
3963
3964
    // build the table
3965
    var size = 1 << maxLen;
3966
    var codes = new Uint32Array(size);
3967
    for (var len = 1, code = 0, skip = 2;
3968
         len <= maxLen;
3969
         ++len, code <<= 1, skip <<= 1) {
3970
      for (var val = 0; val < n; ++val) {
3971
        if (lengths[val] == len) {
3972
          // bit-reverse the code
3973
          var code2 = 0;
3974
          var t = code;
3975
          for (var i = 0; i < len; ++i) {
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable i already seems to be declared on line 3959. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3976
            code2 = (code2 << 1) | (t & 1);
3977
            t >>= 1;
3978
          }
3979
3980
          // fill the table entries
3981
          for (var i = code2; i < size; i += skip)
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable i already seems to be declared on line 3959. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
3982
            codes[i] = (len << 16) | val;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
3983
3984
          ++code;
3985
        }
3986
      }
3987
    }
3988
3989
    return [codes, maxLen];
3990
  };
3991
3992
  constructor.prototype.readBlock = function() {
3993
    function repeat(stream, array, len, offset, what) {
3994
      var repeat = stream.getBits(len) + offset;
3995
      while (repeat-- > 0)
3996
        array[i++] = what;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
Bug introduced by
The variable i is changed as part of the while loop for example by i++ on line 3996. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
3997
    }
3998
3999
    // read block header
4000
    var hdr = this.getBits(3);
4001
    if (hdr & 1)
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
4002
      this.eof = true;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
4003
    hdr >>= 1;
4004
4005
    if (hdr == 0) { // uncompressed block
4006
      var bytes = this.bytes;
4007
      var bytesPos = this.bytesPos;
4008
      var b;
4009
4010
      if (typeof (b = bytes[bytesPos++]) == 'undefined')
4011
        error('Bad block header in flate stream');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
4012
      var blockLen = b;
4013
      if (typeof (b = bytes[bytesPos++]) == 'undefined')
4014
        error('Bad block header in flate stream');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
4015
      blockLen |= (b << 8);
4016
      if (typeof (b = bytes[bytesPos++]) == 'undefined')
4017
        error('Bad block header in flate stream');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
4018
      var check = b;
4019
      if (typeof (b = bytes[bytesPos++]) == 'undefined')
4020
        error('Bad block header in flate stream');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
4021
      check |= (b << 8);
4022
      if (check != (~blockLen & 0xffff))
4023
        error('Bad uncompressed block length in flate stream');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
4024
4025
      this.codeBuf = 0;
4026
      this.codeSize = 0;
4027
4028
      var bufferLength = this.bufferLength;
4029
      var buffer = this.ensureBuffer(bufferLength + blockLen);
4030
      var end = bufferLength + blockLen;
4031
      this.bufferLength = end;
4032
      for (var n = bufferLength; n < end; ++n) {
4033
        if (typeof (b = bytes[bytesPos++]) == 'undefined') {
4034
          this.eof = true;
4035
          break;
4036
        }
4037
        buffer[n] = b;
4038
      }
4039
      this.bytesPos = bytesPos;
4040
      return;
4041
    }
4042
4043
    var litCodeTable;
4044
    var distCodeTable;
4045
    if (hdr == 1) { // compressed block, fixed codes
4046
      litCodeTable = fixedLitCodeTab;
4047
      distCodeTable = fixedDistCodeTab;
4048
    } else if (hdr == 2) { // compressed block, dynamic codes
4049
      var numLitCodes = this.getBits(5) + 257;
4050
      var numDistCodes = this.getBits(5) + 1;
4051
      var numCodeLenCodes = this.getBits(4) + 4;
4052
4053
      // build the code lengths code table
4054
      var codeLenCodeLengths = Array(codeLenCodeMap.length);
4055
      var i = 0;
4056
      while (i < numCodeLenCodes)
4057
        codeLenCodeLengths[codeLenCodeMap[i++]] = this.getBits(3);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
4058
      var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);
4059
4060
      // build the literal and distance code tables
4061
      var len = 0;
4062
      var i = 0;
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable i already seems to be declared on line 4055. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
4063
      var codes = numLitCodes + numDistCodes;
4064
      var codeLengths = new Array(codes);
4065
      while (i < codes) {
4066
        var code = this.getCode(codeLenCodeTab);
4067
        if (code == 16) {
4068
          repeat(this, codeLengths, 2, 3, len);
4069
        } else if (code == 17) {
4070
          repeat(this, codeLengths, 3, 3, len = 0);
4071
        } else if (code == 18) {
4072
          repeat(this, codeLengths, 7, 11, len = 0);
4073
        } else {
4074
          codeLengths[i++] = len = code;
4075
        }
4076
      }
4077
4078
      litCodeTable =
4079
        this.generateHuffmanTable(codeLengths.slice(0, numLitCodes));
4080
      distCodeTable =
4081
        this.generateHuffmanTable(codeLengths.slice(numLitCodes, codes));
4082
    } else {
4083
      error('Unknown block type in flate stream');
4084
    }
4085
4086
    var buffer = this.buffer;
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable buffer already seems to be declared on line 4029. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
4087
    var limit = buffer ? buffer.length : 0;
4088
    var pos = this.bufferLength;
4089
    while (true) {
4090
      var code1 = this.getCode(litCodeTable);
0 ignored issues
show
Bug introduced by
The variable litCodeTable seems to not be initialized for all possible execution paths. Are you sure getCode handles undefined variables?
Loading history...
4091
      if (code1 < 256) {
4092
        if (pos + 1 >= limit) {
4093
          buffer = this.ensureBuffer(pos + 1);
4094
          limit = buffer.length;
4095
        }
4096
        buffer[pos++] = code1;
4097
        continue;
4098
      }
4099
      if (code1 == 256) {
4100
        this.bufferLength = pos;
4101
        return;
4102
      }
4103
      code1 -= 257;
4104
      code1 = lengthDecode[code1];
4105
      var code2 = code1 >> 16;
4106
      if (code2 > 0)
4107
        code2 = this.getBits(code2);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
4108
      var len = (code1 & 0xffff) + code2;
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable len already seems to be declared on line 4061. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
4109
      code1 = this.getCode(distCodeTable);
0 ignored issues
show
Bug introduced by
The variable distCodeTable seems to not be initialized for all possible execution paths. Are you sure getCode handles undefined variables?
Loading history...
4110
      code1 = distDecode[code1];
4111
      code2 = code1 >> 16;
4112
      if (code2 > 0)
4113
        code2 = this.getBits(code2);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
4114
      var dist = (code1 & 0xffff) + code2;
4115
      if (pos + len >= limit) {
4116
        buffer = this.ensureBuffer(pos + len);
4117
        limit = buffer.length;
4118
      }
4119
      for (var k = 0; k < len; ++k, ++pos)
4120
        buffer[pos] = buffer[pos - dist];
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
4121
    }
4122
  };
4123
4124
  return constructor;
4125
})();
4126
// Generated by CoffeeScript 1.4.0
4127
4128
/*
4129
# MIT LICENSE
4130
# Copyright (c) 2011 Devon Govett
4131
# 
4132
# Permission is hereby granted, free of charge, to any person obtaining a copy of this 
4133
# software and associated documentation files (the "Software"), to deal in the Software 
4134
# without restriction, including without limitation the rights to use, copy, modify, merge, 
4135
# publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 
4136
# to whom the Software is furnished to do so, subject to the following conditions:
4137
# 
4138
# The above copyright notice and this permission notice shall be included in all copies or 
4139
# substantial portions of the Software.
4140
# 
4141
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
4142
# BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
4143
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
4144
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
4145
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4146
*/
4147
4148
4149
(function() {
4150
  var PNG;
4151
4152
  PNG = (function() {
4153
    var APNG_BLEND_OP_OVER, APNG_BLEND_OP_SOURCE, APNG_DISPOSE_OP_BACKGROUND, APNG_DISPOSE_OP_NONE, APNG_DISPOSE_OP_PREVIOUS, makeImage, scratchCanvas, scratchCtx;
4154
4155
    PNG.load = function(url, canvas, callback) {
4156
      var xhr,
4157
        _this = this;
0 ignored issues
show
Unused Code introduced by
The variable _this seems to be never used. Consider removing it.
Loading history...
4158
      if (typeof canvas === 'function') {
4159
        callback = canvas;
4160
      }
4161
      xhr = new XMLHttpRequest;
0 ignored issues
show
Bug introduced by
The variable XMLHttpRequest seems to be never declared. If this is a global, consider adding a /** global: XMLHttpRequest */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
4162
      xhr.open("GET", url, true);
4163
      xhr.responseType = "arraybuffer";
4164
      xhr.onload = function() {
4165
        var data, png;
4166
        data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer);
4167
        png = new PNG(data);
4168
        if (typeof (canvas != null ? canvas.getContext : void 0) === 'function') {
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
4169
          png.render(canvas);
4170
        }
4171
        return typeof callback === "function" ? callback(png) : void 0;
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
4172
      };
4173
      return xhr.send(null);
4174
    };
4175
4176
    APNG_DISPOSE_OP_NONE = 0;
0 ignored issues
show
Unused Code introduced by
The variable APNG_DISPOSE_OP_NONE seems to be never used. Consider removing it.
Loading history...
4177
4178
    APNG_DISPOSE_OP_BACKGROUND = 1;
4179
4180
    APNG_DISPOSE_OP_PREVIOUS = 2;
4181
4182
    APNG_BLEND_OP_SOURCE = 0;
4183
4184
    APNG_BLEND_OP_OVER = 1;
0 ignored issues
show
Unused Code introduced by
The variable APNG_BLEND_OP_OVER seems to be never used. Consider removing it.
Loading history...
4185
4186
    function PNG(data) {
4187
      var chunkSize, colors, palLen, delayDen, delayNum, frame, i, index, key, section, short, text, _i, _j, _ref;
4188
      this.data = data;
4189
      this.pos = 8;
4190
      this.palette = [];
4191
      this.imgData = [];
4192
      this.transparency = {};
4193
      this.animation = null;
4194
      this.text = {};
4195
      frame = null;
4196
      while (true) {
4197
        chunkSize = this.readUInt32();
4198
        section = ((function() {
4199
          var _i, _results;
4200
          _results = [];
4201
          for (i = _i = 0; _i < 4; i = ++_i) {
0 ignored issues
show
Unused Code introduced by
The variable i seems to be never used. Consider removing it.
Loading history...
4202
            _results.push(String.fromCharCode(this.data[this.pos++]));
4203
          }
4204
          return _results;
4205
        }).call(this)).join('');
4206
        switch (section) {
4207
          case 'IHDR':
4208
            this.width = this.readUInt32();
4209
            this.height = this.readUInt32();
4210
            this.bits = this.data[this.pos++];
4211
            this.colorType = this.data[this.pos++];
4212
            this.compressionMethod = this.data[this.pos++];
4213
            this.filterMethod = this.data[this.pos++];
4214
            this.interlaceMethod = this.data[this.pos++];
4215
            break;
4216
          case 'acTL':
4217
            this.animation = {
4218
              numFrames: this.readUInt32(),
4219
              numPlays: this.readUInt32() || Infinity,
4220
              frames: []
4221
            };
4222
            break;
4223
          case 'PLTE':
4224
            this.palette = this.read(chunkSize);
4225
            break;
4226
          case 'fcTL':
4227
            if (frame) {
4228
              this.animation.frames.push(frame);
4229
            }
4230
            this.pos += 4;
4231
            frame = {
4232
              width: this.readUInt32(),
4233
              height: this.readUInt32(),
4234
              xOffset: this.readUInt32(),
4235
              yOffset: this.readUInt32()
4236
            };
4237
            delayNum = this.readUInt16();
4238
            delayDen = this.readUInt16() || 100;
4239
            frame.delay = 1000 * delayNum / delayDen;
4240
            frame.disposeOp = this.data[this.pos++];
4241
            frame.blendOp = this.data[this.pos++];
4242
            frame.data = [];
4243
            break;
4244
          case 'IDAT':
4245
          case 'fdAT':
4246
            if (section === 'fdAT') {
4247
              this.pos += 4;
4248
              chunkSize -= 4;
4249
            }
4250
            data = (frame != null ? frame.data : void 0) || this.imgData;
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
4251
            for (i = _i = 0; 0 <= chunkSize ? _i < chunkSize : _i > chunkSize; i = 0 <= chunkSize ? ++_i : --_i) {
4252
              data.push(this.data[this.pos++]);
4253
            }
4254
            break;
4255
          case 'tRNS':
4256
            this.transparency = {};
4257
            switch (this.colorType) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4258
              case 3:
4259
            	palLen = this.palette.length/3;
4260
                this.transparency.indexed = this.read(chunkSize);
4261
                if(this.transparency.indexed.length > palLen)
4262
                	throw new Error('More transparent colors than palette size');
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
4263
                /*
4264
                 * According to the PNG spec trns should be increased to the same size as palette if shorter
4265
                 */
4266
                //short = 255 - this.transparency.indexed.length;
4267
                short = palLen - this.transparency.indexed.length;
4268
                if (short > 0) {
4269
                  for (i = _j = 0; 0 <= short ? _j < short : _j > short; i = 0 <= short ? ++_j : --_j) {
4270
                    this.transparency.indexed.push(255);
4271
                  }
4272
                }
4273
                break;
4274
              case 0:
4275
                this.transparency.grayscale = this.read(chunkSize)[0];
4276
                break;
4277
              case 2:
4278
                this.transparency.rgb = this.read(chunkSize);
4279
            }
4280
            break;
4281
          case 'tEXt':
4282
            text = this.read(chunkSize);
4283
            index = text.indexOf(0);
4284
            key = String.fromCharCode.apply(String, text.slice(0, index));
4285
            this.text[key] = String.fromCharCode.apply(String, text.slice(index + 1));
4286
            break;
4287
          case 'IEND':
4288
            if (frame) {
4289
              this.animation.frames.push(frame);
4290
            }
4291
            this.colors = (function() {
4292
              switch (this.colorType) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4293
                case 0:
4294
                case 3:
4295
                case 4:
4296
                  return 1;
4297
                case 2:
4298
                case 6:
4299
                  return 3;
4300
              }
0 ignored issues
show
Comprehensibility introduced by
There is no default case in this switch, so nothing gets returned when all cases fail. You might want to consider adding a default or return undefined explicitly.
Loading history...
4301
            }).call(this);
4302
            this.hasAlphaChannel = (_ref = this.colorType) === 4 || _ref === 6;
4303
            colors = this.colors + (this.hasAlphaChannel ? 1 : 0);
4304
            this.pixelBitlength = this.bits * colors;
4305
            this.colorSpace = (function() {
4306
              switch (this.colors) {
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4307
                case 1:
4308
                  return 'DeviceGray';
4309
                case 3:
4310
                  return 'DeviceRGB';
4311
              }
0 ignored issues
show
Comprehensibility introduced by
There is no default case in this switch, so nothing gets returned when all cases fail. You might want to consider adding a default or return undefined explicitly.
Loading history...
4312
            }).call(this);
4313
            this.imgData = new Uint8Array(this.imgData);
4314
            return;
4315
          default:
4316
            this.pos += chunkSize;
4317
        }
4318
        this.pos += 4;
4319
        if (this.pos > this.data.length) {
4320
          throw new Error("Incomplete or corrupt PNG file");
4321
        }
4322
      }
4323
      return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
4324
    }
4325
4326
    PNG.prototype.read = function(bytes) {
4327
      var i, _i, _results;
4328
      _results = [];
4329
      for (i = _i = 0; 0 <= bytes ? _i < bytes : _i > bytes; i = 0 <= bytes ? ++_i : --_i) {
0 ignored issues
show
Unused Code introduced by
The variable i seems to be never used. Consider removing it.
Loading history...
4330
        _results.push(this.data[this.pos++]);
4331
      }
4332
      return _results;
4333
    };
4334
4335
    PNG.prototype.readUInt32 = function() {
4336
      var b1, b2, b3, b4;
4337
      b1 = this.data[this.pos++] << 24;
4338
      b2 = this.data[this.pos++] << 16;
4339
      b3 = this.data[this.pos++] << 8;
4340
      b4 = this.data[this.pos++];
4341
      return b1 | b2 | b3 | b4;
4342
    };
4343
4344
    PNG.prototype.readUInt16 = function() {
4345
      var b1, b2;
4346
      b1 = this.data[this.pos++] << 8;
4347
      b2 = this.data[this.pos++];
4348
      return b1 | b2;
4349
    };
4350
4351
    PNG.prototype.decodePixels = function(data) {
4352
      var byte, c, col, i, left, length, p, pa, paeth, pb, pc, pixelBytes, pixels, pos, row, scanlineLength, upper, upperLeft, _i, _j, _k, _l, _m;
4353
      if (data == null) {
4354
        data = this.imgData;
4355
      }
4356
      if (data.length === 0) {
4357
        return new Uint8Array(0);
4358
      }
4359
      data = new FlateStream(data);
4360
      data = data.getBytes();
4361
      pixelBytes = this.pixelBitlength / 8;
4362
      scanlineLength = pixelBytes * this.width;
4363
      pixels = new Uint8Array(scanlineLength * this.height);
4364
      length = data.length;
4365
      row = 0;
4366
      pos = 0;
4367
      c = 0;
4368
      while (pos < length) {
4369 View Code Duplication
        switch (data[pos++]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
4370
          case 0:
4371
            for (i = _i = 0; _i < scanlineLength; i = _i += 1) {
0 ignored issues
show
Unused Code introduced by
The assignment to variable i seems to be never used. Consider removing it.
Loading history...
4372
              pixels[c++] = data[pos++];
4373
            }
4374
            break;
4375
          case 1:
4376
            for (i = _j = 0; _j < scanlineLength; i = _j += 1) {
4377
              byte = data[pos++];
4378
              left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
4379
              pixels[c++] = (byte + left) % 256;
4380
            }
4381
            break;
4382
          case 2:
4383
            for (i = _k = 0; _k < scanlineLength; i = _k += 1) {
4384
              byte = data[pos++];
4385
              col = (i - (i % pixelBytes)) / pixelBytes;
4386
              upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
4387
              pixels[c++] = (upper + byte) % 256;
4388
            }
4389
            break;
4390
          case 3:
4391
            for (i = _l = 0; _l < scanlineLength; i = _l += 1) {
4392
              byte = data[pos++];
4393
              col = (i - (i % pixelBytes)) / pixelBytes;
4394
              left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
4395
              upper = row && pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
4396
              pixels[c++] = (byte + Math.floor((left + upper) / 2)) % 256;
4397
            }
4398
            break;
4399
          case 4:
4400
            for (i = _m = 0; _m < scanlineLength; i = _m += 1) {
4401
              byte = data[pos++];
4402
              col = (i - (i % pixelBytes)) / pixelBytes;
4403
              left = i < pixelBytes ? 0 : pixels[c - pixelBytes];
4404
              if (row === 0) {
4405
                upper = upperLeft = 0;
4406
              } else {
4407
                upper = pixels[(row - 1) * scanlineLength + col * pixelBytes + (i % pixelBytes)];
4408
                upperLeft = col && pixels[(row - 1) * scanlineLength + (col - 1) * pixelBytes + (i % pixelBytes)];
4409
              }
4410
              p = left + upper - upperLeft;
4411
              pa = Math.abs(p - left);
4412
              pb = Math.abs(p - upper);
4413
              pc = Math.abs(p - upperLeft);
4414
              if (pa <= pb && pa <= pc) {
4415
                paeth = left;
4416
              } else if (pb <= pc) {
4417
                paeth = upper;
4418
              } else {
4419
                paeth = upperLeft;
4420
              }
4421
              pixels[c++] = (byte + paeth) % 256;
4422
            }
4423
            break;
4424
          default:
4425
            throw new Error("Invalid filter algorithm: " + data[pos - 1]);
4426
        }
4427
        row++;
4428
      }
4429
      return pixels;
4430
    };
4431
4432
    PNG.prototype.decodePalette = function() {
4433
      var c, i, length, palette, pos, ret, transparency, _i, _ref, _ref1;
4434
      palette = this.palette;
4435
      transparency = this.transparency.indexed || [];
4436
      ret = new Uint8Array((transparency.length || 0) + palette.length);
4437
      pos = 0;
4438
      length = palette.length;
4439
      c = 0;
4440
      for (i = _i = 0, _ref = palette.length; _i < _ref; i = _i += 3) {
4441
        ret[pos++] = palette[i];
4442
        ret[pos++] = palette[i + 1];
4443
        ret[pos++] = palette[i + 2];
4444
        ret[pos++] = (_ref1 = transparency[c++]) != null ? _ref1 : 255;
4445
      }
4446
      return ret;
4447
    };
4448
4449
    PNG.prototype.copyToImageData = function(imageData, pixels) {
4450
      var alpha, colors, data, i, input, j, k, length, palette, v, _ref;
4451
      colors = this.colors;
4452
      palette = null;
4453
      alpha = this.hasAlphaChannel;
4454
      if (this.palette.length) {
4455
        palette = (_ref = this._decodedPalette) != null ? _ref : this._decodedPalette = this.decodePalette();
4456
        colors = 4;
4457
        alpha = true;
4458
      }
4459
      data = imageData.data || imageData;
4460
      length = data.length;
4461
      input = palette || pixels;
4462
      i = j = 0;
4463
      if (colors === 1) {
4464
        while (i < length) {
4465
          k = palette ? pixels[i / 4] * 4 : j;
4466
          v = input[k++];
4467
          data[i++] = v;
4468
          data[i++] = v;
4469
          data[i++] = v;
4470
          data[i++] = alpha ? input[k++] : 255;
4471
          j = k;
4472
        }
4473
      } else {
4474
        while (i < length) {
4475
          k = palette ? pixels[i / 4] * 4 : j;
4476
          data[i++] = input[k++];
4477
          data[i++] = input[k++];
4478
          data[i++] = input[k++];
4479
          data[i++] = alpha ? input[k++] : 255;
4480
          j = k;
4481
        }
4482
      }
4483
    };
4484
4485
    PNG.prototype.decode = function() {
4486
      var ret;
4487
      ret = new Uint8Array(this.width * this.height * 4);
4488
      this.copyToImageData(ret, this.decodePixels());
4489
      return ret;
4490
    };
4491
4492
    scratchCanvas = document.createElement('canvas');
4493
4494
    scratchCtx = scratchCanvas.getContext('2d');
4495
4496
    makeImage = function(imageData) {
4497
      var img;
4498
      scratchCtx.width = imageData.width;
4499
      scratchCtx.height = imageData.height;
4500
      scratchCtx.clearRect(0, 0, imageData.width, imageData.height);
4501
      scratchCtx.putImageData(imageData, 0, 0);
4502
      img = new Image;
0 ignored issues
show
Bug introduced by
The variable Image seems to be never declared. If this is a global, consider adding a /** global: Image */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
4503
      img.src = scratchCanvas.toDataURL();
4504
      return img;
4505
    };
4506
4507
    PNG.prototype.decodeFrames = function(ctx) {
4508
      var frame, i, imageData, pixels, _i, _len, _ref, _results;
4509
      if (!this.animation) {
4510
        return;
4511
      }
4512
      _ref = this.animation.frames;
4513
      _results = [];
4514
      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
4515
        frame = _ref[i];
4516
        imageData = ctx.createImageData(frame.width, frame.height);
4517
        pixels = this.decodePixels(new Uint8Array(frame.data));
4518
        this.copyToImageData(imageData, pixels);
4519
        frame.imageData = imageData;
4520
        _results.push(frame.image = makeImage(imageData));
4521
      }
4522
      return _results;
4523
    };
4524
4525
    PNG.prototype.renderFrame = function(ctx, number) {
4526
      var frame, frames, prev;
4527
      frames = this.animation.frames;
4528
      frame = frames[number];
4529
      prev = frames[number - 1];
4530
      if (number === 0) {
4531
        ctx.clearRect(0, 0, this.width, this.height);
4532
      }
4533
      if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_BACKGROUND) {
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
4534
        ctx.clearRect(prev.xOffset, prev.yOffset, prev.width, prev.height);
4535
      } else if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_PREVIOUS) {
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
4536
        ctx.putImageData(prev.imageData, prev.xOffset, prev.yOffset);
4537
      }
4538
      if (frame.blendOp === APNG_BLEND_OP_SOURCE) {
4539
        ctx.clearRect(frame.xOffset, frame.yOffset, frame.width, frame.height);
4540
      }
4541
      return ctx.drawImage(frame.image, frame.xOffset, frame.yOffset);
4542
    };
4543
4544
    PNG.prototype.animate = function(ctx) {
4545
      var doFrame, frameNumber, frames, numFrames, numPlays, _ref,
4546
        _this = this;
4547
      frameNumber = 0;
4548
      _ref = this.animation, numFrames = _ref.numFrames, frames = _ref.frames, numPlays = _ref.numPlays;
0 ignored issues
show
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
4549
      return (doFrame = function() {
4550
        var f, frame;
4551
        f = frameNumber++ % numFrames;
4552
        frame = frames[f];
4553
        _this.renderFrame(ctx, f);
4554
        if (numFrames > 1 && frameNumber / numFrames < numPlays) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if numFrames > 1 && frameNu... / numFrames < numPlays is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
4555
          return _this.animation._timeout = setTimeout(doFrame, frame.delay);
4556
        }
4557
      })();
4558
    };
4559
4560
    PNG.prototype.stopAnimation = function() {
4561
      var _ref;
4562
      return clearTimeout((_ref = this.animation) != null ? _ref._timeout : void 0);
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
4563
    };
4564
4565
    PNG.prototype.render = function(canvas) {
4566
      var ctx, data;
4567
      if (canvas._png) {
4568
        canvas._png.stopAnimation();
4569
      }
4570
      canvas._png = this;
4571
      canvas.width = this.width;
4572
      canvas.height = this.height;
4573
      ctx = canvas.getContext("2d");
4574
      if (this.animation) {
4575
        this.decodeFrames(ctx);
4576
        return this.animate(ctx);
4577
      } else {
4578
        data = ctx.createImageData(this.width, this.height);
4579
        this.copyToImageData(data, this.decodePixels());
4580
        return ctx.putImageData(data, 0, 0);
4581
      }
4582
    };
4583
4584
    return PNG;
4585
4586
  })();
4587
4588
  window.PNG = PNG;
4589
4590
}).call(this);
4591